﻿/*
   KeyCodeVastra theme
   -------------------
   Hand-written, no framework. Bootstrap and jQuery were removed from the
   scaffold deliberately; nothing here reintroduces them.

   Palette comes from the product banner: deep green, brass gold, cream ground.
*/

:root {
    /*  THIS IS A LIGHT APPLICATION, AND THE BROWSER HAS TO BE TOLD.

        Owner, 03-09: "sometimes list is showing like this" - the browser's own
        suggestion list under Sale code drawn as white text on black, in the
        middle of a cream screen.

        That list is not ours and no rule in this file can reach it. Chrome
        draws its autofill dropdown - and native <select> popups, datalists,
        date pickers and scrollbars - in whatever colour scheme the PAGE
        declares, and a page that declares none inherits the operating
        system's. So on a machine set to dark mode every piece of browser
        furniture went dark while everything we draw stayed cream. It came and
        went with the OS setting, which is why it looked intermittent.

        One line fixes all of it: this palette has exactly one mode, and
        saying so is simply true rather than a workaround. If a dark theme is
        ever built, this becomes "light dark" and the tokens below grow a
        second set - see the note there.  */
    color-scheme: light;

    /* Brand */
    --green: #12382B;
    --green-700: #0d2a20;
    --green-500: #1c5340;
    --green-300: #4c8271;
    --gold: #C9A227;
    --gold-600: #a9871c;
    --gold-100: #f6ecca;

    /*  THE "THIS ONE IS SELECTED" WASH - owner, 09-09: "set background colour
        of [the tab] which is active", about the Details / Prices / Stock row.

        IT WAS NEVER DEFINED. Five rules in company.css read
        var(--accent-soft, #efe7d4) and there was no such variable anywhere, so
        every one of them had been rendering the fallback - #efe7d4 against a
        #F7F1E4 page, a difference of about two percent. The active tab was
        painted; it just could not be seen. Exactly the trap CLAUDE.md names
        first, in a stylesheet rather than a view.

        Deeper than gold-100 so it reads as chosen against BOTH the cream page
        and a white card, and still light enough to keep --ink comfortably
        readable on it.  */
    --accent-soft: #f0e2b4;
    --cream: #F7F1E4;
    --card: #FFFFFF;

    /* Ink */
    --ink: #1b1f1d;
    --ink-soft: #4d5754;
    --ink-faint: #7d8784;

    /* Lines and state */
    --line: #e2dccc;
    --line-strong: #cdc4ad;
    --ok: #1f7a4d;
    --ok-bg: #e8f5ee;
    --warn: #9a6a06;
    --warn-bg: #fdf3dc;
    --bad: #a52222;
    --bad-bg: #fdecec;

    /* Shape */
    --radius: 10px;
    --radius-sm: 6px;
    --shadow: 0 1px 2px rgba(18, 56, 43, .06), 0 8px 24px rgba(18, 56, 43, .07);
    --shadow-sm: 0 1px 2px rgba(18, 56, 43, .08);
    --ring: 0 0 0 3px rgba(201, 162, 39, .35);

    /* Type */
    --font: "Segoe UI", system-ui, -apple-system, "Helvetica Neue", Arial, sans-serif;
    --mono: ui-monospace, "Cascadia Mono", Consolas, "Courier New", monospace;
}

*, *::before, *::after { box-sizing: border-box; }

/*  [hidden] MEANS HIDDEN. ONCE, HERE, FOR EVERYTHING.

    The browser hides [hidden] with display:none from its OWN stylesheet, which
    every author rule outranks. So the moment a class says `display: flex` - or
    grid, or inline-flex - the element it is on can never be hidden by the
    attribute again, and a script doing `el.hidden = true` silently does
    nothing at all.

    THIS PROJECT HAD PATCHED IT NINE TIMES, one class at a time: .ad-panel,
    .im-f, .btn, .im-bc-add, .im-bc-head, .im-bc-piece, .im-bc-hist,
    .im-pc-shared and .pa-pick-opt, several with a note saying it would happen
    again. The tenth was the till's Cash+UPI split, which stayed on screen in
    Cash mode - owner, 11-09: "total default not showing in cash", of a Cash
    box that had no business being there at all.

    A TENTH PATCH WOULD HAVE BEEN THE WRONG ANSWER. Every one of those is the
    same bug wearing a different class name, and the next block anybody writes
    with a display and a `hidden` would have been the eleventh. The failure is
    always the same shape too: markup that is plainly right, a script that
    plainly sets the flag, and a screen that ignores both - so it is looked for
    everywhere except the stylesheet.

    Checked before it was written: every [hidden] rule in this application sets
    display:none. Nothing anywhere wants a hidden element shown, so this can
    only ever agree with what the code already meant.

    !important is not decoration here - it is the whole mechanism. Without it
    an author display still wins and this rule changes nothing.

    The four rules in company.css are now redundant. They are left where they
    are: each carries the reasoning that led here, and deleting them would take
    that with it. */
[hidden] { display: none !important; }

html { -webkit-text-size-adjust: 100%; }

body {
    margin: 0;
    background: var(--cream);
    color: var(--ink);
    font-family: var(--font);
    font-size: 15px;
    line-height: 1.55;
}

h1, h2, h3, h4 {
    margin: 0 0 .5rem;
    color: var(--green);
    font-weight: 650;
    line-height: 1.25;
}

h1 { font-size: 1.6rem; }
h2 { font-size: 1.2rem; }
h3 { font-size: 1rem; }

p { margin: 0 0 .75rem; }

a {
    color: var(--green-500);
    text-decoration-color: var(--line-strong);
    text-underline-offset: 2px;
}

a:hover { color: var(--gold-600); }

code, kbd, samp { font-family: var(--mono); font-size: .86em; }

kbd {
    padding: .1rem .35rem;
    border: 1px solid var(--line-strong);
    border-bottom-width: 2px;
    border-radius: 4px;
    background: #fff;
    color: var(--ink-soft);
    font-size: .78rem;
    white-space: nowrap;
}

/* ---------- Layout ---------- */

.shell { display: flex; flex-direction: column; min-height: 100vh; }

.wrap {
    width: 100%;
    max-width: 1080px;
    margin-inline: auto;
    padding-inline: 1.25rem;
}

.main { flex: 1; padding-block: 1.75rem 3rem; }

.topbar {
    background: var(--green);
    color: #fff;
    box-shadow: var(--shadow-sm);
}

.topbar .wrap {
    display: flex;
    align-items: center;
    gap: 1rem;
    min-height: 58px;
}

.brand {
    display: flex;
    align-items: baseline;
    gap: .5rem;
    color: #fff;
    font-size: 1.05rem;
    font-weight: 650;
    letter-spacing: .01em;
    text-decoration: none;
}

.brand b { color: var(--gold); font-weight: 700; }

.brand small {
    color: rgba(255, 255, 255, .62);
    font-size: .72rem;
    font-weight: 400;
    letter-spacing: .04em;
    text-transform: uppercase;
}

.topbar nav { margin-left: auto; display: flex; gap: .25rem; }

.topbar nav a {
    padding: .35rem .7rem;
    border-radius: var(--radius-sm);
    color: rgba(255, 255, 255, .85);
    font-size: .9rem;
    text-decoration: none;
}

.topbar nav a:hover { background: rgba(255, 255, 255, .1); color: #fff; }

.footer {
    padding-block: 1rem;
    border-top: 1px solid var(--line);
    color: var(--ink-faint);
    font-size: .82rem;
}

.footer .wrap { display: flex; flex-wrap: wrap; gap: .75rem; align-items: center; }
.footer .spacer { margin-left: auto; }

/* ---------- Cards ---------- */

.card {
    margin-bottom: 1.25rem;
    padding: 1.15rem 1.25rem;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--card);
    box-shadow: var(--shadow-sm);
}

.card > :last-child { margin-bottom: 0; }

.card-head {
    display: flex;
    align-items: center;
    gap: .6rem;
    margin-bottom: .9rem;
    padding-bottom: .7rem;
    border-bottom: 1px solid var(--line);
}

.card-head h2, .card-head h1 { margin: 0; }
.card-head .spacer { margin-left: auto; }

.lede { color: var(--ink-soft); }

.grid {
    display: grid;
    gap: 1.25rem;
    grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
}

/* ---------- Forms ---------- */

.field { margin-bottom: .9rem; }

.field > label {
    display: block;
    margin-bottom: .3rem;
    color: var(--ink-soft);
    font-size: .82rem;
    font-weight: 600;
    letter-spacing: .01em;
}

.field .hint { margin: .25rem 0 0; color: var(--ink-faint); font-size: .78rem; }

/*  Every text-like box, however it was written.

    This used to be a list of input[type="..."] selectors, which quietly missed
    every <input> with no type attribute at all - most of SuperAdmin/Content and
    all of the company register form. A bare <input> BEHAVES as text but does
    not MATCH input[type="text"], so those boxes kept the browser's default
    ~210px width and none of our border, padding or font. Hence the ragged
    columns on those two screens.

    Naming what must NOT be full width is the safer direction: a control added
    later is styled unless it is listed here. */
input:not([type="checkbox"], [type="radio"], [type="file"], [type="range"],
          [type="color"], [type="submit"], [type="button"], [type="reset"],
          [type="image"], [type="hidden"]),
select, textarea {
    width: 100%;
    padding: .5rem .65rem;
    border: 1px solid var(--line-strong);
    border-radius: var(--radius-sm);
    background: #fff;
    color: var(--ink);
    font-family: inherit;
    font-size: .95rem;
    transition: border-color .12s, box-shadow .12s;
}

textarea { min-height: 5rem; resize: vertical; }

input:focus-visible, select:focus-visible, textarea:focus-visible {
    border-color: var(--gold);
    box-shadow: var(--ring);
    outline: none;
}

input:disabled, select:disabled, textarea:disabled {
    background: #f6f4ee;
    color: var(--ink-faint);
}

/*  NO SPINNERS ON ANY NUMBER BOX, ANYWHERE.

    Owner, 03-09 for the item master, then 04-09 for the rest: "all numeric
    entry should remove steppers; where required I will do for that only."

    So this is the DEFAULT, and a stepper is the exception somebody asks for by
    name. It started as one screen's rule and it should not have: a number box
    on the purchase grid is the same kind of thing as one on the item master,
    and a control that appears on some screens and not others is a control
    nobody trusts.

    WHY THE ARROWS ARE UNWANTED HERE. Every number box in this application is
    money, a percentage or a quantity:

      * the step is 0.01 on money - nobody prices a garment by clicking up four
        hundred times, and a mis-click moves a rate by a paisa, silently;
      * the boxes are packed and narrow, and the buttons eat the right-hand end
        of a field already showing 18500.00;
      * these forms are KEYED, not clicked - an operator tabs through
        twenty-five boxes, and a control only a mouse can reach is in the way.

    BOTH HALVES ARE NEEDED. WebKit and Blink draw the arrows as a pseudo
    element that has to be switched off; Firefox draws them as part of the
    control, which appearance: textfield removes. Either alone leaves half the
    browsers still showing them.

    THE KEYBOARD'S OWN ARROWS ARE A SEPARATE QUESTION and are answered
    elsewhere: app.js walks the fields with them, precisely because a hidden
    stepper that still responds to Up would be worse than a visible one. See
    "Keyboard - the whole contract" in the skill.

    TO PUT ONE BACK, on a box where stepping is genuinely wanted, add
    `class="has-stepper"` to that input. Nothing uses it yet.  */
input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button {
    -webkit-appearance: none;
    appearance: none;
    margin: 0;
}

input[type="number"] {
    -moz-appearance: textfield;
    appearance: textfield;
}

input[type="number"].has-stepper {
    -moz-appearance: auto;
    appearance: auto;
}
input[type="number"].has-stepper::-webkit-outer-spin-button,
input[type="number"].has-stepper::-webkit-inner-spin-button {
    -webkit-appearance: auto;
    appearance: auto;
}

/* Set by app.js when the server sends errors back for named fields. */
.field.is-invalid input,
.field.is-invalid select,
.field.is-invalid textarea { border-color: var(--bad); }

.field-error {
    display: block;
    margin-top: .25rem;
    color: var(--bad);
    font-size: .78rem;
}

.row {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
    align-items: center;
}

/*  Every image on the site is stored as a path in a text field. Typing one is
    fine for whoever built the site and hopeless for whoever runs it, so
    app.js turns any [data-image] input into a field with a Browse button and
    a thumbnail beside it. These are the rules for what it builds - shared by
    SuperAdmin and the Company area, since both grow one of these fields. */

.pick { display: flex; align-items: center; gap: 9px; }
.pick input { flex: 1 1 auto; min-width: 0; }
.pick .btn { flex: 0 0 auto; white-space: nowrap; }

/* Always present, even when empty, so adding a picture does not shift the row. */
.pick-thumb {
    flex: 0 0 auto;
    width: 42px;
    height: 42px;
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    background: #f6f4ec center / cover no-repeat;
    position: relative;
}

/* The empty state: a quiet cross, not an error. */
.pick-thumb.is-empty::after {
    content: "";
    position: absolute;
    inset: 0;
    background:
        linear-gradient(45deg,  transparent 47%, var(--line-strong) 47%, var(--line-strong) 53%, transparent 53%),
        linear-gradient(-45deg, transparent 47%, var(--line-strong) 47%, var(--line-strong) 53%, transparent 53%);
    opacity: .55;
}

.pick.is-busy { opacity: .6; pointer-events: none; }

/* ---------- Buttons ---------- */

.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: .4rem;
    padding: .48rem .95rem;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    background: #fff;
    color: var(--ink);
    font: inherit;
    font-size: .9rem;
    font-weight: 600;
    cursor: pointer;
    transition: background-color .12s, border-color .12s, color .12s;
}

.btn:focus-visible { box-shadow: var(--ring); outline: none; }

.btn[disabled] { opacity: .55; cursor: default; }

.btn-primary { background: var(--green); color: #fff; }
.btn-primary:hover:not([disabled]) { background: var(--green-500); }

.btn-accent { background: var(--gold); color: #22200f; }
.btn-accent:hover:not([disabled]) { background: var(--gold-600); color: #fff; }

.btn-quiet { border-color: var(--line-strong); color: var(--ink-soft); }
.btn-quiet:hover:not([disabled]) { border-color: var(--green-300); color: var(--green); }

.btn kbd {
    border-color: rgba(0, 0, 0, .18);
    background: rgba(255, 255, 255, .22);
    color: inherit;
    opacity: .8;
}

.btn-primary kbd { border-color: rgba(255, 255, 255, .35); }

/* ---------- Status ---------- */

.pill {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    padding: .12rem .55rem;
    border-radius: 999px;
    font-size: .75rem;
    font-weight: 650;
    letter-spacing: .02em;
}

.pill::before {
    content: "";
    width: .45rem;
    height: .45rem;
    border-radius: 50%;
    background: currentColor;
}

.pill-ok { background: var(--ok-bg); color: var(--ok); }
.pill-bad { background: var(--bad-bg); color: var(--bad); }
.pill-warn { background: var(--warn-bg); color: var(--warn); }

.note {
    margin-bottom: 1rem;
    padding: .7rem .85rem;
    border: 1px solid var(--line);
    border-left: 3px solid var(--ink-faint);
    border-radius: var(--radius-sm);
    font-size: .9rem;
}

.note > :last-child { margin-bottom: 0; }
.note-ok { border-left-color: var(--ok); background: var(--ok-bg); }
.note-bad { border-left-color: var(--bad); background: var(--bad-bg); }
.note-warn { border-left-color: var(--warn); background: var(--warn-bg); }

/* ---------- Facts and tables ---------- */

.facts { margin: 0; display: grid; gap: .1rem .9rem; grid-template-columns: max-content 1fr; }
.facts dt { color: var(--ink-faint); font-size: .82rem; }
.facts dd { margin: 0; font-size: .9rem; overflow-wrap: anywhere; }
.facts dd.mono { font-family: var(--mono); font-size: .82rem; }

table { width: 100%; border-collapse: collapse; }

th, td {
    padding: .45rem .6rem;
    border-bottom: 1px solid var(--line);
    text-align: left;
    vertical-align: top;
}

th {
    color: var(--ink-faint);
    font-size: .76rem;
    font-weight: 650;
    letter-spacing: .04em;
    text-transform: uppercase;
}

tbody tr:last-child td { border-bottom: none; }

.swatches { display: flex; flex-wrap: wrap; gap: .6rem; }

.swatch {
    flex: 1 1 120px;
    padding: .55rem .6rem;
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    font-size: .72rem;
}

.swatch i {
    display: block;
    height: 2.4rem;
    margin-bottom: .45rem;
    border: 1px solid rgba(0, 0, 0, .08);
    border-radius: 4px;
}

.swatch b { display: block; font-size: .8rem; }
.swatch span { color: var(--ink-faint); font-family: var(--mono); }

details > summary {
    cursor: pointer;
    color: var(--ink-soft);
    font-size: .85rem;
    font-weight: 600;
}

details[open] > summary { margin-bottom: .75rem; }

pre {
    margin: 0;
    padding: .75rem;
    overflow-x: auto;
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    background: #fbf9f3;
    color: var(--ink-soft);
    font-family: var(--mono);
    font-size: .76rem;
    line-height: 1.5;
}

/* ---------- Toasts ---------- */

.toasts {
    position: fixed;
    right: 1rem;
    bottom: 1rem;
    z-index: 50;
    display: flex;
    flex-direction: column;
    gap: .5rem;
    width: min(28rem, calc(100vw - 2rem));
}

.toast {
    padding: .7rem .85rem;
    border: 1px solid var(--line);
    border-left: 3px solid var(--green);
    border-radius: var(--radius-sm);
    background: var(--card);
    box-shadow: var(--shadow);
    font-size: .88rem;
    animation: toast-in .16s ease-out;
}

.toast strong { display: block; color: var(--green); }
.toast p { margin: .15rem 0 0; color: var(--ink-soft); font-size: .82rem; }
.toast-bad { border-left-color: var(--bad); }
.toast-bad strong { color: var(--bad); }
.toast-ok { border-left-color: var(--ok); }
.toast-ok strong { color: var(--ok); }

/*  A third kind, and the business parameters are why it exists. "This is under
    the margin the shop set" is not a refusal - the sale may well go ahead, at
    the owner's discretion - so it must not wear the same red as something that
    was rejected. Red that turns out not to have stopped anything is red that
    gets ignored the next time it does. */
.toast-warn { border-left-color: var(--warn); background: var(--warn-bg); }
.toast-warn strong { color: var(--warn); }

.toast.is-leaving { animation: toast-out .16s ease-in forwards; }

/* ===================== the failure dialog - owner, 11-09 ==================
   "Show alert box popup or error popup if any error or exception."

   IN theme.css AND NOT company.css, which is the only structural decision
   here. A failure can happen on any page this application serves - signing
   in, registering a company, the SuperAdmin panel - and every one of those
   loads theme.css while only the company screens load company.css. Written
   over there it would have been a dialog with no styling at all on exactly
   the pages where something had already gone wrong.

   For the same reason it borrows nothing from .co-dialog and stands on its
   own. It does use .pill, .mono and .btn, which are all in this file.

   IT LOOKS LIKE THE ERROR PAGE ON PURPOSE (Views/Shared/Error.cshtml): the
   same heading, the same red status pill, the same facts list, the same
   collapsible developer detail. One event, one appearance, whether it
   arrived through a fetch or a navigation. ============================== */
.kcv-err {
    width: min(560px, calc(100vw - 32px));
    padding: 20px 22px;
    border: 1px solid var(--line);
    /*  The one piece of colour: a failure is not a form. */
    border-top: 3px solid var(--bad);
    border-radius: var(--radius);
    background: var(--card);
    color: var(--ink);
    box-shadow: var(--shadow);
}

/*  Darker than a question's backdrop. This one is not to be clicked past -
    the dialog ignores backdrop clicks - so the page behind it is put
    properly out of the way rather than half-dimmed. */
.kcv-err::backdrop { background: rgba(18, 22, 20, .55); }

.kcv-err-top { display: flex; align-items: flex-start; gap: 10px; }
/*  The message is the heading, and a SQL message can be a long sentence, so
    it wraps rather than being trimmed. Nothing here is decorative enough to
    be worth losing a word of. */
.kcv-err-top h3 { margin: 0; font-size: 1.02rem; line-height: 1.35; flex: 1 1 auto; }
.kcv-err-top .pill { flex: 0 0 auto; }

.kcv-err-detail { margin: .6rem 0 0; color: var(--ink-soft); font-size: .9rem; }

.kcv-err-facts {
    margin: .9rem 0 0;
    display: grid;
    gap: .1rem .9rem;
    grid-template-columns: max-content 1fr;
}
.kcv-err-facts dt { color: var(--ink-faint); font-size: .82rem; }
.kcv-err-facts dd {
    margin: 0;
    font-family: var(--mono);
    font-size: .8rem;
    /*  A request id has no spaces in it and will happily run off the side of
        the dialog. It is the one thing on here somebody has to read back
        character by character, so it breaks instead. */
    overflow-wrap: anywhere;
}

/*  "3 more problems happened while this was open" - see errorBox in app.js.
    Quiet, because it is a footnote about the dialog and not about the
    failure the dialog is for. */
.kcv-err-more { margin: .8rem 0 0; color: var(--warn); font-size: .82rem; }

.kcv-err-dev { margin: .9rem 0 0; }
.kcv-err-dev summary { cursor: pointer; color: var(--ink-faint); font-size: .82rem; }
.kcv-err-dev pre {
    margin: .5rem 0 .5rem;
    padding: 10px;
    /*  A stack is tall and wide and neither can be allowed to grow the
        dialog past the screen: it scrolls in its own box. */
    max-height: 240px;
    overflow: auto;
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    background: var(--bg);
    font-family: var(--mono);
    font-size: .74rem;
    line-height: 1.5;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}
.kcv-err-copy { padding: .25rem .6rem; font-size: .78rem; }

/*  One way out, on the right, where every other dialog in this application
    puts its closing button. */
.kcv-err-foot { display: flex; justify-content: flex-end; margin-top: 18px; }

@keyframes toast-in {
    from { opacity: 0; transform: translateY(.4rem); }
}

@keyframes toast-out {
    to { opacity: 0; transform: translateY(.4rem); }
}

/* A form is dimmed, not replaced, while its fetch is in flight. */
.is-busy { opacity: .6; pointer-events: none; }

@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: .001ms !important;
        transition-duration: .001ms !important;
    }
}

@media (max-width: 640px) {
    .topbar .wrap { min-height: 52px; }
    .brand small { display: none; }
    .facts { grid-template-columns: 1fr; }
    .facts dd { margin-bottom: .4rem; }
}

/* ---------------------------------------------------- show the password ---

   The reveal button app.js puts inside every password box - owner, 07-09,
   asking for it on My details.

   IT LIVES IN theme.css AND NOT company.css on purpose: password fields are
   on sign-in, sign-up and reset as well as on the company screens, and those
   pages load this sheet and not that one. Styling it there would have given
   the button no size and no position on exactly the three pages a password
   matters most on. */
.pwd-wrap {
    position: relative;
    display: block;
}

/* Room for the button, so a long password does not run underneath it. */
.pwd-wrap > input {
    width: 100%;
    padding-right: 30px;
}

.pwd-eye {
    position: absolute;
    top: 1px;
    right: 1px;
    bottom: 1px;
    width: 28px;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    border: 0;
    background: none;
    cursor: pointer;
    color: var(--ink-faint, #6b7280);
    border-radius: 0 6px 6px 0;
}

.pwd-eye:hover { color: var(--green, #12382B); }

/* Shown, not hidden - the eye is "on", so it reads as the state the box is
   in rather than as the button that was last pressed. */
.pwd-eye.is-on { color: var(--gold, #b8860b); }
