/*
 * The board's palette, washes and swatches.
 *
 * SHARED with Spacecamp by copy (docs/board-port.md): this file must stay
 * byte-identical in both apps, so nothing Orbit-specific belongs in it. It is
 * split out of app.css because the board SETTINGS page draws labels and
 * swatches too, and it is an ordinary page that loads neither Vue nor
 * board.css. Imported from app.js right after app.css; the comments below say
 * what depends on that order.
 */

/*
 * ------------------------------------------------------- the board palette
 *
 * Ten colours from the design's tokens (Figma, "list/*", Oct 2026), each in
 * three shades with the design's own roles:
 *
 *   --orb-{c}         SOLID — a label pill, a picker swatch, a board's wash.
 *                      Carries --orb-ink, never white: these are light colours
 *                      and the design pairs every one with ink at 4.5:1 or
 *                      better. White on Kōwhai would be about 1.4:1.
 *   --orb-{c}-strong  dots, borders, a lane's accent bar, a selected ring —
 *                      3:1 or better on white and on its own tint.
 *   --orb-{c}-tint    a lane's background, a board tile's head; body text on it.
 *
 * Keep the names in step with App\Entity\BoardColour — every class name is
 * built from the stored value (`red`, not `pohutukawa`), so the palette can be
 * retuned without a data migration. The names people see are
 * BoardColour::label().
 *
 * These are in app.css rather than in the board island's own board.css because
 * the board SETTINGS page draws labels and swatches too, and it is an ordinary
 * Bootstrap page that loads neither Vue nor board.css. A second copy of the
 * hexes is exactly how the "red" list and the "red" label stop being the
 * same red.
 *
 * Fixed rather than a free-form colour picker: arbitrary colours produce boards
 * where nothing is distinguishable at a glance, and nobody owns the contrast of
 * the text sitting on them.
 */
:root {
    --orb-ink:           #17181a;
    /* Pōhutukawa */
    --orb-red:           #ff5f5b;
    --orb-red-strong:    #d73337;
    --orb-red-tint:      #ffeae6;
    /* Kūmara */
    --orb-orange:        #ff8e31;
    --orb-orange-strong: #e06700;
    --orb-orange-tint:   #ffeddc;
    /* Kōwhai */
    --orb-yellow:        #ffd200;
    --orb-yellow-strong: #ad8700;
    --orb-yellow-tint:   #fdf3d6;
    /* Feijoa */
    --orb-lime:          #a3dd42;
    --orb-lime-strong:   #679c00;
    --orb-lime-tint:     #ebf9dc;
    /* Harakeke */
    --orb-green:         #47cf79;
    --orb-green-strong:  #00a350;
    --orb-green-tint:    #e2fbe7;
    /* Pāua */
    --orb-teal:          #1ad1d1;
    --orb-teal-strong:   #009d9d;
    --orb-teal-tint:     #defaf9;
    /* Moana */
    --orb-blue:          #57a8ff;
    --orb-blue-strong:   #2f82d6;
    --orb-blue-tint:     #e4f6ff;
    /* Kina */
    --orb-purple:        #ac83f9;
    --orb-purple-strong: #885ed0;
    --orb-purple-tint:   #f6efff;
    /* Tamarillo */
    --orb-pink:          #f46eb4;
    --orb-pink-strong:   #ca488f;
    --orb-pink-tint:     #ffe9f7;
    /* Greywacke */
    --orb-grey:          #a4acb4;
    --orb-grey-strong:   #80878f;
    --orb-grey-tint:     #f2f4f6;
}

.orb-label-red,    .orb-swatch-red    { background: var(--orb-red); }
.orb-label-orange, .orb-swatch-orange { background: var(--orb-orange); }
.orb-label-yellow, .orb-swatch-yellow { background: var(--orb-yellow); }
.orb-label-lime,   .orb-swatch-lime   { background: var(--orb-lime); }
.orb-label-green,  .orb-swatch-green  { background: var(--orb-green); }
.orb-label-teal,   .orb-swatch-teal   { background: var(--orb-teal); }
.orb-label-blue,   .orb-swatch-blue   { background: var(--orb-blue); }
.orb-label-purple, .orb-swatch-purple { background: var(--orb-purple); }
.orb-label-pink,   .orb-swatch-pink   { background: var(--orb-pink); }
.orb-label-grey,   .orb-swatch-grey   { background: var(--orb-grey); }

/* A label wherever one is drawn: on a card face, in a card's panel, and in the
   list on the settings page. */
.orb-label {
    display: inline-block;
    border: 0;
    border-radius: 0.2rem;
    padding: 0.1rem 0.4rem;
    font-size: 0.7rem;
    font-weight: 700;
    line-height: 1.4;
    min-width: 2.2rem;
    color: var(--orb-ink);
}

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

/*
 * A colour swatch. It had no size of its own until the settings page needed
 * one — the colour classes above set a background and nothing else, so every
 * swatch in the lane and label pickers was an empty button collapsed to
 * nothing. Anything that draws a swatch wants this class as well as its
 * colour.
 */
.orb-swatch {
    width: 1.25rem;
    height: 1.25rem;
    flex: 0 0 auto;
    border: 0;
    border-radius: 0.25rem;
    padding: 0;
    cursor: pointer;
}

.orb-swatch-on {
    outline: 2px solid var(--bs-body-color);
    outline-offset: 1px;
}

/* "No colour", which is what a lane and a board background start as. A ring
   rather than a fill, because the absence has to look like an option. */
.orb-swatch-none {
    background: transparent;
    border: 1px dashed var(--bs-secondary-color);
}

/*
 * The settings page picks a colour with real radio buttons rather than
 * JavaScript, so the form works the way a form does — keyboard, back button,
 * no-JS and all. The input is hidden and its label is the swatch; :checked and
 * :focus-visible on the input draw the state onto the label beside it.
 */
.orb-swatch-radio {
    position: absolute;
    width: 0;
    height: 0;
    opacity: 0;
}

.orb-swatch-radio:checked + .orb-swatch {
    outline: 2px solid var(--bs-body-color);
    outline-offset: 1px;
}

.orb-swatch-radio:focus-visible + .orb-swatch {
    outline: 2px solid var(--bs-link-color);
    outline-offset: 2px;
}

.orb-label-list {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.orb-label-row {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-wrap: wrap;
}

.orb-label-row .form-control { flex: 1 1 8rem; }

/* The current background, shown at the shape it is actually used in — cropped
   to fill, not letterboxed, so a picture that will be cut off looks cut off
   here rather than on the board. */
.orb-bg-preview {
    display: block;
    width: 100%;
    max-height: 10rem;
    object-fit: cover;
    border-radius: 0.35rem;
}

/*
 * The colour wash.
 *
 * **55%, and the number is the whole point.** This was 16% first, by analogy
 * with a coloured lane's tint — and it was wrong, because the two are not the
 * same problem. A lane tint is a small block sitting beside untinted lanes, so
 * a hint of colour reads as a difference; a board background has nothing next
 * to it to be compared against, so 16% of a mid-blue over white is #dbe5ef and
 * the honest description of that is "white". Somebody who picks blue and gets a
 * board they cannot tell from the default one concludes the setting is broken,
 * which is exactly what happened.
 *
 * Its base is each colour's SOLID shade, which the design already pairs with
 * ink at 6:1 or better; 55% of it over white only raises that, to 9.6:1 on
 * Pōhutukawa, the darkest of the ten. (Under the old, darker eight this figure
 * was the ceiling for contrast; with the design's light set it is a choice of
 * look, and could go as high as 100% without losing readability.) What it
 * does NOT protect is anything painted in a fixed colour of its own —
 * Bootstrap's link blue, `btn-outline-secondary`'s grey — which is what
 * `--orb-on-backdrop` below is for: text sitting directly on the backdrop reads
 * its colour from that token, never from a Bootstrap utility.
 *
 * The flat background is declared first as the fallback for anything without
 * color-mix(): a neutral that is right in both themes, not a hard-coded pastel
 * that would be a light smudge on a dark board.
 *
 * These live in app.css, with the palette, because two things paint them: the
 * board page puts one on <body>, and the settings page shows the same wash as a
 * preview so that pressing Save visibly does something. Defining the mix twice
 * is how the preview and the board would come to disagree.
 */

/*
 * What is behind the page, and what colour text painted straight onto it
 * should be. The defaults describe a plain board. They are declared on `body`
 * at (0,0,1) so that a wash class at (0,1,0) wins whatever the file order —
 * and they MUST stay in this file rather than move to board.css, which loads
 * after it: a default declared there would out-cascade the derivation below
 * and every wash would silently go back to a fixed colour.
 */
body {
    --orb-backdrop: var(--bs-body-bg);
    --orb-on-backdrop: var(--bs-body-color);
}

/* Each wash names its base colour once; the mix itself is stated once, below. */
.orb-wash-red    { --orb-wash-base: var(--orb-red); }
.orb-wash-orange { --orb-wash-base: var(--orb-orange); }
.orb-wash-yellow { --orb-wash-base: var(--orb-yellow); }
.orb-wash-lime   { --orb-wash-base: var(--orb-lime); }
.orb-wash-green  { --orb-wash-base: var(--orb-green); }
.orb-wash-teal   { --orb-wash-base: var(--orb-teal); }
.orb-wash-blue   { --orb-wash-base: var(--orb-blue); }
.orb-wash-purple { --orb-wash-base: var(--orb-purple); }
.orb-wash-pink   { --orb-wash-base: var(--orb-pink); }
.orb-wash-grey   { --orb-wash-base: var(--orb-grey); }

.orb-wash-red,
.orb-wash-orange,
.orb-wash-yellow,
.orb-wash-lime,
.orb-wash-green,
.orb-wash-teal,
.orb-wash-blue,
.orb-wash-purple,
.orb-wash-pink,
.orb-wash-grey {
    background-color: var(--bs-secondary-bg);
    --orb-backdrop: color-mix(in srgb, var(--orb-wash-base) 55%, var(--bs-body-bg));
    background-color: var(--orb-backdrop);

    /*
     * Black or white, decided by the wash's own lightness rather than by a
     * table: relative colour syntax reads the wash's oklch L, and the clamp
     * turns "L below the threshold" into 1 (white) and "above it" into 0
     * (black). Chroma 0, so it is a true grey either way.
     *
     * The threshold: black and white have equal WCAG contrast on a grey of
     * L ≈ 0.56; 0.6 leans white on mid tones, which is what people prefer to
     * read. Every one of the ten washes sits at L 0.81 or above, so all of
     * them come out black — at 9.6:1 or better.
     *
     * A browser without relative colour syntax (before Chrome 119, Safari 16.4,
     * Firefox 128) makes this value invalid at computed-value time, so a
     * `color: var(--orb-on-backdrop)` falls back to the inherited body colour
     * — ink, which is the right answer on every wash anyway.
     */
    --orb-on-backdrop: oklch(from var(--orb-backdrop) clamp(0, (0.6 / l - 1) * infinity, 1) 0 h);
}

/*
 * A photo the backdrop-luminance controller measured as dark. The scrim over
 * it goes dark too (board.css), so the mirror of the theme is the right text:
 * its background colour, white in the light theme.
 */
.orb-backdrop-dark {
    --orb-on-backdrop: var(--bs-body-bg);
}

/* The preview of it on the settings page: the wash at the shape a board is,
   so "blue" is answered with the actual colour rather than with the word. */
.orb-wash-preview {
    display: flex;
    align-items: flex-end;
    gap: 0.4rem;
    height: 6rem;
    padding: 0.5rem;
    border: 1px solid var(--bs-border-color);
    border-radius: 0.35rem;
    background-color: var(--bs-body-bg);
    overflow: hidden;
}

/* Two stand-in lanes. Without them the preview is a rectangle of colour, which
   does not answer the question people actually have — whether the board will
   still be readable. */
.orb-wash-preview span {
    flex: 0 0 3.5rem;
    border: 1px solid var(--bs-border-color);
    border-radius: 0.35rem;
    background: var(--bs-secondary-bg);
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.18);
}

.orb-wash-preview span:first-child { height: 80%; }
.orb-wash-preview span:last-child  { height: 55%; }
