/* The arrangement this renderer puts around makeover's components.

   makeover styles a component's depth, fill, edge and colour. What it has no
   word for is everything `vocabulary::OWN` holds: how a screen divides its
   width, how a region stacks what it holds, how a row lines its parts up, where
   a menu hangs. Those names come out of this crate on every host, so their
   geometry is written once here rather than once per app. An app that never
   wrote it served a wall of unspaced text on every described screen.

   Under makeover and under the app. The layer statement is `reset, quasi,
   makeover, ...app`, so a theme and an app both override anything here without
   reaching for specificity, and nothing here can override them. An app's reset
   goes in `reset`: anywhere later, `* { padding: 0 }` zeroes every padded
   screen and row this file draws.

   Every value is a token or a custom property with a fallback. How wide a
   screen runs is the one place an app is expected to answer differently, and it
   answers by setting `--measure-wide`, `--measure-contained` or
   `--measure-reading`, never by restating a rule. */

@layer quasi {
    /* --- Screens ---------------------------------------------------------- */

    main.single {
        padding: var(--gap-page);
    }

    main.list-detail,
    main.list-detail-tabbed,
    main.sidebar-content {
        display: grid;
        grid-template-columns: var(--region-share, 1fr) var(--region-rest, 1fr);
        gap: var(--gap-pane);
        align-content: start;
        padding: var(--gap-page);
    }

    /* A band divides no width: it is the strip over or under the columns. */
    main > .region.band {
        grid-column: 1 / -1;
        display: flex;
        flex-wrap: wrap;
        align-items: center;
        gap: var(--gap-section);
    }

    /* One content region makes the two-column grid a lie. */
    main:not(:has(> .region:not(.band) ~ .region:not(.band))) > .region:not(.band) {
        grid-column: 1 / -1;
    }

    /* How wide a screen runs, which is a separate question from how its width
       divides. `auto` margins on a growing flex item resolve to nothing, so a
       host whose main fills a flex row is not moved by them. */
    main.measure-wide {
        max-width: var(--measure-wide, none);
        margin-inline: auto;
    }

    main.measure-contained {
        max-width: var(--measure-contained, 87.5rem);
        margin-inline: auto;
    }

    main.measure-reading {
        max-width: var(--measure-reading, 42rem);
        margin-inline: auto;
    }

    /* A notice belongs to the screen rather than to a place in it. */
    main > .notices {
        grid-column: 1 / -1;
        display: flex;
        flex-direction: column;
        gap: var(--gap-peer);
    }

    /* --- Regions ---------------------------------------------------------- */

    /* A grid child refuses to shrink below its content unless told to, and
       `relative` is what `.anchored` positions against. */
    .region {
        min-width: 0;
        position: relative;
    }

    /* No `min-height: 0`. Nothing here gives a region its own scroll, so the
       only thing it bought was letting a grid row crush the region inside a
       screen of fixed height, and the region's flex children with it: a
       window whose screen is the scrollport drew its import buttons over the
       sentences beside them. */
    .region.pane,
    .region.sidebar,
    .region.group,
    .bespoke,
    .widget {
        display: flex;
        flex-direction: column;
        gap: var(--gap-group);
        min-width: 0;
    }

    /* A control in a stack is as wide as what it says. Stretched, a lone
       button reads as a bar across the region. */
    .region > .button,
    .region > .link,
    .region > .chip {
        align-self: flex-start;
    }

    /* A group after other content starts a new section, so it sits further
       from what precedes it than two things inside one section do. */
    .region:not(.tiles) > .region.group:not(:first-child),
    .region > .heading:not(:first-child) {
        margin-block-start: var(--gap-group);
    }

    /* A set of peers: a group holding groups and nothing else, which the
       renderer marks `tiles` and lifts each member of with makeover's
       `raised`. As many columns as fit at a card's least width, and a card as
       tall as the tallest beside it. An app sets `--tile-min` to change how
       narrow a card may go. */
    .region.tiles {
        display: grid;
        grid-template-columns: repeat(auto-fill, minmax(min(100%, var(--tile-min, 16rem)), 1fr));
        gap: var(--gap-section);
    }

    .region.group.raised {
        padding: var(--gap-section);
        gap: var(--gap-peer);
    }

    /* A card is read at a glance, so the rows in it sit as a list rather
       than as a stack of lines each asking to be pressed. */
    .region.group.raised .row {
        padding-block: var(--gap-bound);
    }

    /* A group that is not a card is a group box: an edge cut into the region
       it sits in, with its first heading notched into the top rule as its
       legend. The Platinum specimen's group box (wiki `look-restoration`, "the
       notched group box"), which no generation shipped.

       Only a plain group directly inside a region that is not itself a group.
       A raised group is a card and already an object, and a group inside a
       group box is a subsection of it, so neither takes a second frame. The
       legend's fill is the raised surface a region draws on, which is what
       breaks the rule behind it. */
    .region:not(.group) > .region.group:not(.raised):not(.tiles) {
        position: relative;
        padding: var(--gap-pane) var(--gap-pane) var(--gap-section);
        box-shadow: var(--bevel-inset);
        border-radius: var(--radius-fine, 0);
        margin-block-start: 0.75lh;
    }

    .region:not(.group) > .region.group:not(.raised):not(.tiles) > .heading:first-child {
        position: absolute;
        inset-block-start: -0.75lh;
        inset-inline-start: var(--gap-group);
        margin: 0;
        padding-inline: var(--gap-peer);
        background: var(--surface-raised);
        font-size: var(--text-note);
        font-weight: bold;
        letter-spacing: 0.02em;
    }

    /* A group box with nothing in it yet draws nothing. A region a write or a
       picker answers into is described empty and filled by the swap, and every
       region carries its hidden anchored container, so `:empty` never matches:
       what counts as nothing is a group whose only children are that hidden
       container. Drawn framed, it read as an input with no label. Hidden rather
       than unframed, so the stack's gap does not keep a slot for it; the swap
       replaces the whole region, and the answer it brings has children.

       Wherever the group sits, not only directly in a region that is not a
       group. Inside a group box it draws no frame, but it still took the
       stack's gap and a section's margin, which left a blank band under a
       switch whose note had not arrived yet (MNW Payments' Tips). */
    .region.group:not(.raised):not(.tiles):not(:has(> :not(.anchored[hidden]))) {
        display: none;
    }

    .region-consults {
        display: flex;
        flex-direction: column;
        gap: var(--gap-peer);
    }

    /* A menu's container, carrying `hidden` until something opens it. */
    .anchored {
        position: absolute;
        z-index: 800;
    }

    /* --- Text ------------------------------------------------------------- */

    .heading {
        line-height: 1.2;
        margin: 0;
    }

    h1.heading {
        font-size: var(--text-title);
    }

    h2.heading {
        font-size: var(--text-head);
    }

    h3.heading,
    h4.heading,
    h5.heading,
    h6.heading {
        font-size: var(--text-subhead);
    }

    .text {
        margin: 0;
        max-width: 68ch;
    }

    .rich {
        max-width: 68ch;
    }

    .rich > * {
        margin-block: 0;
    }

    .rich > * + * {
        margin-block-start: var(--gap-peer);
    }

    .rich :is(ul, ol) {
        padding-inline-start: 2ch;
    }

    .clock {
        font-family: var(--font-mono, monospace);
        font-variant-numeric: tabular-nums;
    }

    /* --- Figures, forms, fields ------------------------------------------- */

    .figure-act {
        display: block;
        color: inherit;
        text-decoration: none;
    }

    .form {
        display: flex;
        flex-direction: column;
        gap: var(--gap-group);
    }

    /* A run's members sit a peer's gap apart. makeover's rule makes it a row
       and says nothing about the space between, so two fields placed beside
       each other drew with their edges touching. */
    .run {
        gap: var(--gap-peer);
    }

    /* The submit that ends a form stands away from the fields above it, as
       wide as its label. */
    .act-submit {
        align-self: flex-start;
        margin-block-start: var(--gap-peer);
    }

    .field-writes {
        display: flex;
        flex-direction: column;
        gap: var(--gap-bound);
    }

    .field-consults,
    .field-suggests {
        display: flex;
        flex-wrap: wrap;
        align-items: center;
        gap: var(--gap-bound);
    }

    .chip-remove {
        margin-inline-start: var(--gap-bound);
    }

    .selector {
        display: flex;
        flex-wrap: wrap;
        align-items: center;
        gap: var(--gap-bound);
    }

    /* A tab group is its strip and then its panes, stacked, and the pane that
       is up fills the width. It used to share `.selector`'s wrapping row, so any
       pane narrower than the room left beside the strip sat next to it, centred
       on the pane's height, and no two tabs were the same width. */
    .tabgroup {
        display: flex;
        flex-direction: column;
        gap: var(--gap-bound);
    }

    .tabgroup > .showing-frame {
        min-inline-size: 0;
    }

    /* `Strip::Down`: the strip is a column beside its panes. The row wraps, so
       when the panes would get less than half the group, or less than the
       16rem a region reads at, the strip folds over them instead: room the
       browser measures rather than a breakpoint anybody typed, which is the
       room ruling's line. Half alone let a 300px group keep a 150px pane. */
    .tabgroup[data-strip="down"] {
        flex-direction: row;
        flex-wrap: wrap;
        align-items: flex-start;
        column-gap: var(--gap-section);
    }

    .tabgroup[data-strip="down"] > :not(.showing-frame) {
        flex: 1 1 auto;
        max-inline-size: 100%;
    }

    .tabgroup[data-strip="down"] > .showing-frame {
        flex: 999 1 0;
        min-inline-size: min(100%, max(50%, 16rem));
    }

    .selector[aria-orientation="vertical"] {
        flex-direction: column;
        flex-wrap: nowrap;
        align-items: stretch;
    }

    /* An anchor is an action as often as a button is. Resting colour and
       underline only: makeover's fill, tone and disabled arms are a layer
       above and keep winning. */
    a.button,
    a.chip,
    a.row,
    a.figure,
    a.rest-page,
    a.rest-previous,
    a.rest-next {
        color: inherit;
        text-decoration: none;
    }

    /* --- Controls ---------------------------------------------------------- */

    /* makeover draws a control's fill, bevel and states and leaves its box to
       the page. The box, then: what a control needs to read as one whether
       it is a `button` or an anchor, before an app says anything. */
    .button,
    .chip,
    .tab {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        gap: var(--gap-bound);
        font: inherit;
        line-height: 1.2;
        cursor: pointer;
        text-decoration: none;
    }

    .button,
    .tab {
        padding: var(--gap-peer) var(--gap-section);
    }

    .chip {
        padding: var(--step-tight) var(--step-roomy);
    }

    .field {
        font: inherit;
        padding: var(--gap-peer) var(--gap-group);
        min-width: 0;
    }

    /* A figure is a number over what the number is. makeover colours the two
       parts and both are spans, so without this they run together as "6Active
       Creators". */
    .figure {
        display: flex;
        flex-direction: column;
        gap: var(--gap-bound);
    }

    /* --- Rows ------------------------------------------------------------- */

    /* A row is a line of parts. makeover colours the parts and says nothing
       about the line. */
    /* Wraps, so a row too narrow for its parts puts the actions on a line of
       their own instead of pushing the document sideways. */
    .row {
        display: flex;
        flex-wrap: wrap;
        align-items: baseline;
        gap: var(--gap-section);
        padding-block: var(--gap-peer);
    }

    /* The actions end the line, whatever else the row carries. How a part
       holds its tokens and controls is makeover's, from makeover-webview
       0.82.0; where the part sits in the row is this sheet's. */
    .row > .row-actions {
        margin-inline-start: auto;
    }

    .row-select,
    .row-menu {
        flex: 0 0 auto;
    }

    /* The row's primary made into a control: in flow and filling the line. */
    .row-activate {
        flex: 1 1 auto;
        min-width: 0;
        color: inherit;
        text-decoration: none;
    }

    /* Hover says a press does something, so only a row that has something to
       press answers the pointer. */
    @media (hover: hover) and (pointer: fine) {
        .row:is(a, [hx-get], :has(> .row-activate, > .row-select)):hover {
            background: var(--row-hover, color-mix(in srgb, var(--content) 9%, transparent));
        }
    }

    /* Chosen is what a click did, selected is what a checkbox holds, current
       is where the keyboard is. */
    .row.row-selected,
    .row.row-chosen,
    .table-row.table-row-selected,
    .table-row.table-row-chosen {
        background: color-mix(in srgb, var(--action) 28%, transparent);
    }

    .row-current,
    .table-row-current {
        box-shadow: inset 3px 0 0 var(--action);
    }

    /* A row's menu is a `details` whose summary is the More button. What it
       holds hangs under the row from the row's end, over the rows that follow.

       From the row rather than from the button, because a table cell clips
       what overflows it and an open menu is nothing but overflow. Only the row
       is positioned, so no cell between the two is the menu's containing block
       and none can clip it. */
    .row:has(> .row-menu),
    .table-row:has(> .table-menu) {
        position: relative;
    }

    .row-menu > summary,
    .table-row-menu > summary {
        list-style: none;
        cursor: pointer;
    }

    .row-menu > summary::-webkit-details-marker,
    .table-row-menu > summary::-webkit-details-marker {
        display: none;
    }

    .row-menu-items {
        position: absolute;
        inset-block-start: 100%;
        inset-inline-end: 0;
        z-index: 800;
        display: flex;
        flex-direction: column;
        align-items: stretch;
        gap: var(--gap-bound);
        padding: var(--gap-bound);
        background: var(--surface-overlay, var(--surface-raised));
        box-shadow: var(--elevation-overlay, var(--bevel-raised));
    }

    /* What an act asks for before it fires: the press opens a box of fields
       under it, over whatever follows, the way a row's menu hangs. */
    .ask {
        position: relative;
    }

    .ask-open {
        list-style: none;
        cursor: pointer;
    }

    .ask-open::-webkit-details-marker {
        display: none;
    }

    .ask-body {
        position: absolute;
        inset-block-start: calc(100% + var(--gap-bound));
        inset-inline-end: 0;
        z-index: 800;
        display: flex;
        flex-direction: column;
        gap: var(--gap-peer);
        min-inline-size: 16rem;
        padding: var(--gap-group);
        white-space: normal;
        background: var(--surface-overlay, var(--surface-raised));
        box-shadow: var(--elevation-overlay, var(--bevel-raised));
    }

    /* --- Tables ----------------------------------------------------------- */

    /* No gutter rule here. This layer sits under makeover's, whose cell rule
       gives every cell an 8ch basis, so a gutter is sized by the floor class it
       carries (node.rs): `min-2` for a tick or a chevron, `min-8` for More. */

    /* The heading owns the type, the fill and the caret; a native button would
       draw its own chrome over all three. */
    .table-sort {
        background: none;
        border: 0;
        box-shadow: none;
        padding: 0;
        font: inherit;
        color: inherit;
        text-align: inherit;
        cursor: pointer;
        user-select: none;
    }

    /* --- Paging ----------------------------------------------------------- */

    .rest {
        display: flex;
        align-items: center;
        flex-wrap: wrap;
        gap: var(--gap-section);
        padding-block: var(--gap-group);
    }

    .rest-position {
        margin-inline-end: auto;
    }

    .rest-pages {
        display: flex;
        align-items: center;
        gap: var(--gap-bound);
        margin: 0;
        padding: 0;
        list-style: none;
    }

    .rest-page-here {
        font-weight: 600;
    }

    /* --- Frame ------------------------------------------------------------ */

    .frame {
        display: flex;
        flex-direction: column;
        gap: var(--gap-group);
        min-height: 0;
    }

    .frame-status {
        display: flex;
        align-items: center;
        gap: var(--gap-section);
    }

    .frame-verbs {
        display: flex;
        align-items: center;
        flex-wrap: wrap;
        gap: var(--gap-bound);
    }
}
