/*
 * The palette and shared facts. Three laws: colour — one wheel for the machine, grey for the
 * tool; presence — steps of φ; space — the module halved or doubled. No number below stands
 * outside them.
 *
 * Shared by the machjs tools: the inspector publishes it as `@evgkch/machjs-inspector/tokens.css`
 * (the widgets require it — custom properties are inherited into their shadow roots, rules are
 * not), the examples import it beside their own stylesheets.
 */

/*
 * Two layers, in this order: `tokens` holds the custom properties, `controls` the pressable and
 * typable boxes built out of them. A page that adds a layer of its own — `@layer tokens, page;`
 * — appends it after these, because the order is fixed here, at the first mention, and this file
 * is imported before any rule of the page.
 */
@layer tokens, controls;

@layer tokens {
    :root {
        --main-font: "Onest", "Inter", sans-serif;
        --mono-font: ui-monospace, SFMono-Regular, Menlo, monospace;

        /* Onest has no italic — allow a synthetic slant, never a synthetic weight. */
        font-synthesis: style;
        text-rendering: optimizeLegibility;
        -webkit-font-smoothing: antialiased;
        -moz-osx-font-smoothing: grayscale;

        /*
     * Three sizes of monospace for three uses: the source (read at length), a name in a drawing,
     * a number or title. 15:12:10 is 5:4 and 6:5; the code's 13 stands off the ladder because it
     * is read by the line, not the word.
     */
        --code: 13px;
        --name: 0.75rem;
        --micro: 0.625rem;

        /*
     * The module: one row of the figure, one line of the source, one slice of the run. The same
     * number as `grid.ts` declares, present before any script runs so `var(--cell)` needs no
     * fallback.
     */
        --cell: 24px;

        /*
     * One height for every pressable and typable box, so a line of controls has no height
     * wobble. The module and a half: a control is taller than a row of the figure because a
     * finger lands on it and a row does not. `--control-sm` is the module and a quarter, for a
     * dense strip standing inside another control.
     */
        --control: var(--step-6);
        --control-sm: calc(var(--cell) + var(--step-2));

        /*
     * The text inside a control, and the smaller one beside it. Off the monospace ladder above:
     * that ladder is for the figure, this size is read as prose in a button or a field.
     */
        --ui: 0.875rem;
        --ui-sm: 0.8125rem;

        /*
     * All spacing is the module halved and doubled: 3 6 12 18 24 36 — no two distances close
     * enough to be mistaken. In pixels, because the figure is drawn on a 24px pixel grid.
     */
        --step-1: 3px;
        --step-2: 6px;
        --step-3: 12px;
        --step-4: 18px;
        --step-5: 24px;
        --step-6: 36px;

        /* One duration, one curve. */
        --quick: 0.12s;
        --ease: cubic-bezier(0.2, 0.7, 0.3, 1);

        /*
     * Layering is a border and a value step, no shadows (the floating overlay casts one). One
     * ladder of lightness at one hue; the dark scheme is the same ladder from the other end.
     */
        --bg: oklch(96.5% 0.004 264);
        --surface: oklch(100% 0 0);
        --ink: oklch(22% 0.012 264);
        --muted: oklch(52% 0.014 264);
        --faint: oklch(68% 0.012 264);
        --line: oklch(91% 0.006 264);
        --line-firm: oklch(85.5% 0.008 264);

        /*
     * Colour means the machine; everything the tool says about itself is grey with a cool cast.
     * The wheel belongs to the states, with the warm quadrant reserved for the two non-states:
     * what a rule emits, and what is wrong.
     */
        --accent: oklch(38% 0.035 264);
        --warn: oklch(54% 0.19 25);

        /* Λ is the other axis, coloured — warmer than any lane, so no state is mistaken for an
       output. */
        --emit: oklch(56% 0.14 75);

        /*
     * Two radii at 3:2: surfaces and the things inside them. Generous, because a superellipse
     * leaves the edge late — a small radius would show none of the shape.
     */
        --radius: 36px;
        --radius-sm: 12px;

        /*
     * One colour per state, cycling after eight; every surface reads the same variable. One
     * lightness and one chroma for all — states are equal, only the hue turns. Eight even steps
     * of the wheel minus the warm quadrant, dealt so the first three are maximally far apart.
     */
        --lane-l: 56%;
        --lane-c: 0.155;
        --lane-0: oklch(var(--lane-l) var(--lane-c) 241);
        --lane-1: oklch(var(--lane-l) var(--lane-c) 139);
        --lane-2: oklch(var(--lane-l) var(--lane-c) 343);
        --lane-3: oklch(var(--lane-l) var(--lane-c) 173);
        --lane-4: oklch(var(--lane-l) var(--lane-c) 309);
        --lane-5: oklch(var(--lane-l) var(--lane-c) 105);
        --lane-6: oklch(var(--lane-l) var(--lane-c) 275);
        --lane-7: oklch(var(--lane-l) var(--lane-c) 207);

        /*
     * Presence, in steps of φ: 10, 16, 26, 42.
     *
     *   wash       the ground: a rail, a string, a tint under the pointer
     *   wash-firm  a row you are standing on, a band, a mark in the gutter
     *   wash-hard  the body of a cell, and selected text
     *   wash-full  the edge of a cell, and what is reachable but not in one step
     */
        --wash: 10%;
        --wash-firm: 16%;
        --wash-hard: 26%;
        --wash-full: 42%;

        /*
     * The same ladder downwards: φ⁻¹, its square, its cube. Quiet — a dead rule, still read.
     * Dim — out of reach. Undone — a step walked back past.
     */
        --quiet: 0.618;
        --dim: 0.382;
        --undone: 0.236;
    }

    @media (prefers-color-scheme: dark) {
        :root {
            --bg: oklch(13.5% 0.012 264);
            --surface: oklch(18.5% 0.012 264);
            --ink: oklch(96% 0.006 264);
            --muted: oklch(70% 0.012 264);
            --faint: oklch(54% 0.012 264);
            --line: oklch(27% 0.012 264);
            --line-firm: oklch(33% 0.014 264);

            --accent: oklch(90% 0.02 264);
            --warn: oklch(74% 0.16 28);
            --emit: oklch(82% 0.13 75);

            /* Lighter and slightly less chromatic — the same colour on a dark ground. The hues do
           not move. */
            --lane-l: 76%;
            --lane-c: 0.13;
        }
    }

    * {
        box-sizing: border-box;
    }

    /* Panel names. One height in all three panels — the figure and the run line up row for row. */
    .tag,
    .label {
        margin: 0;
        font: 500 var(--micro)/1 var(--main-font);
        letter-spacing: 0.09em;
        text-transform: uppercase;
        color: var(--faint);
    }

    /*
 * Chrome 139+: every corner on the page, the tabs and the state chip included. The property
 * does nothing where the radius is 0, so one rule covers everything that has a frame.
 */
    @supports (corner-shape: superellipse(1.25)) {
        * {
            corner-shape: superellipse(1.25);
        }
    }

    @media (prefers-reduced-motion: reduce) {
        * {
            transition: none !important;
        }
    }
}

/*
 * The controls: the pressable and typable boxes, out of the properties above. Here rather than in
 * every page, because a button of one height beside a field of another is the one flaw a shared
 * palette cannot hide — and three pages that each wrote their own had drifted to three.
 *
 * A page overrides any of this from its own layer; `@layer tokens, controls;` at the head of this
 * file puts both below whatever the page declares after them.
 */
@layer controls {
    /*
   * One box, two roles. `--control` is the height of all of them, so a row of mixed controls has
   * a single baseline and a single top edge.
   */
    :where(button, .button, input, select, textarea) {
        height: var(--control);
        border: 1px solid var(--line);
        border-radius: var(--radius-sm);
        background: var(--surface);
        color: var(--ink);
        font: 400 var(--ui) / 1 var(--main-font);
        transition:
            border-color var(--quick) var(--ease),
            background-color var(--quick) var(--ease),
            color var(--quick) var(--ease);
    }

    /* Pressed rather than typed into: a firmer edge, wider sides, and the weight of a word. */
    :where(button, .button) {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        gap: var(--step-2);
        padding: 0 var(--step-4);
        border-color: var(--line-firm);
        font-weight: 500;
        white-space: nowrap;
        cursor: pointer;
    }

    :where(button, .button):hover:not(:disabled, [aria-disabled="true"]) {
        border-color: var(--accent);
        color: var(--accent);
    }

    /*
   * Off because the machine says so. On the example pages every control is enabled by `can()`
   * and by nothing else, so what is faded here is exactly what the schema has no rule for from
   * where the machine stands.
   */
    :where(button, .button):disabled,
    :where(button, .button)[aria-disabled="true"] {
        opacity: var(--dim);
        cursor: not-allowed;
    }

    /* Typed into: the ground of the page rather than the surface, so the well reads as a well. */
    :where(input, select, textarea) {
        min-width: 0;
        padding: 0 var(--step-3);
        background: var(--bg);
    }

    /* The one control whose height is its content's. */
    :where(textarea) {
        height: auto;
        padding: var(--step-3);
        line-height: 1.55;
        resize: vertical;
    }

    /* Room on the right for the arrow the browser draws. */
    :where(select) {
        padding-right: var(--step-5);
        cursor: pointer;
    }

    :where(input, textarea)::placeholder {
        color: var(--faint);
    }

    /* Locked because the machine says so — the field is still read, so it is faded and not hidden. */
    :where(input, textarea):read-only {
        opacity: var(--quiet);
    }

    :where(input, select, textarea):hover:not(:disabled, :read-only) {
        border-color: var(--line-firm);
    }

    :where(input, select, textarea):focus-visible,
    :where(button, .button):focus-visible {
        outline: 2px solid var(--accent);
        outline-offset: var(--step-1);
    }

    /* What a check found, on the control it found it on. */
    :where(input, select, textarea)[aria-invalid="true"] {
        border-color: var(--warn);
    }

    /* A dense strip inside another control — a segmented switch, a stepper. */
    :where(.dense) :where(button, .button, input, select) {
        height: var(--control-sm);
        padding: 0 var(--step-3);
        font-size: var(--ui-sm);
    }

    /* A key of the keyboard, named in running text. Pressable in look only. */
    :where(kbd) {
        display: inline-block;
        padding: 0 0.32em;
        border: 1px solid var(--line-firm);
        border-bottom-width: 2px;
        border-radius: var(--step-1);
        background: var(--bg);
        color: var(--ink);
        font: inherit;
        font-size: 0.85em;
    }
}
/* One mount, and everything below is inside it. Two inspectors on a screen are two of these. */

@layer tokens, controls, page;

@layer page {
    .machjs-inspector {
        display: grid;
        min-width: 0;
        min-height: 0;
        height: 100%;
    }

    /*
 * The figure and the history: beside if the board fits whole, under if not — the mount measures
 * and puts the class on. Exploring there is no history, and the figure has the whole surface.
 */
    .work {
        /* The least history worth standing beside the figure: eight slices. In pixels, because the
       mount reads it with `parseFloat`. */
        --history-min: 192px;

        display: grid;
        grid-template-columns: minmax(0, 1fr);
        grid-template-rows: minmax(0, 1fr) auto;
        gap: var(--step-4);
        min-height: 0;
        height: 100%;
        /* Both hug what is in them vertically: a figure with room to spare is a figure, not a field. */
        align-items: start;
    }

    /* Beside: the figure column is the board's width (`--board`, set by the mount), the history
   takes the rest with `--history-min` as its floor — the number the mount tested against. */
    .work.beside {
        grid-template-columns: var(--board, minmax(0, 1fr)) minmax(
                var(--history-min),
                1fr
            );
        grid-template-rows: minmax(0, 1fr);
    }
}
