/*
 * Cards and the row of cards.
 *
 * core.md §4 puts three demands on this file, and every rule below serves one of them:
 *
 * 1. Cards in one row line up — the card itself, its header and its footer. That is why the
 *    grid stretches its items and the card is a column with a growing body: the footers then
 *    land on one line without anyone measuring anything.
 * 2. A label-and-value list inside a card is built as columns: labels left, values right,
 *    figures aligned to the right edge.
 * 3. The approximation mark, the currency code and the glyphs must not drift from row to row,
 *    which is what the separate currency column is for.
 */

/* --- Row of cards -------------------------------------------------------------------- */

.app-cards {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
    /* Stretch, not start: a short card grows to the height of the tallest one in the row. */
    align-items: stretch;
    gap: var(--space-5);
}

.app-cards--4 {
    grid-template-columns: repeat(4, minmax(0, 1fr));
}

/* --- The summary panel ---------------------------------------------------------------- */

/*
 * The statistics of a layer, and of a single object, in one shape.
 *
 * One white panel divided into columns, never a row of cards: cards are objects the owner
 * acts on, and four of them standing over a list of four more said the wrong thing twice —
 * that the statistics are objects, and that the objects are as important as the statistics.
 * The same kind of statement gets the same shape everywhere (core.md §1.4), so a list page and
 * the page of one object draw their figures alike.
 *
 * The dividing lines are the gaps: a one-pixel grid gap over a border-coloured ground shows
 * through between the columns, and it goes on working when the columns wrap onto a second row,
 * where a border on one side would have to know which side that is.
 */
.app-summary {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 1px;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    /* Shows through the gaps and nowhere else: the columns cover the rest of it. */
    background: var(--border);
    overflow: hidden;
}

.app-summary__part {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    min-width: 0;
    padding: var(--space-4);
    background: var(--surface);
}

.app-summary__title {
    font-size: var(--fs-card);
    font-weight: var(--fw-semibold);
    line-height: var(--lh-tight);
}

.app-summary__body {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}

/*
 * The bottom line of a column, pushed to the bottom of the panel.
 *
 * margin-top: auto is what makes the four bottom lines stand at one height without anyone
 * measuring them — the same thing the equal-height footers of four cards used to do
 * (core.md §4.4).
 */
.app-summary__foot {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin-top: auto;
    padding-top: var(--space-3);
    border-top: 1px solid var(--surface-2);
}

/* The label sits left, the figure right, whatever the width of either. */
.app-summary__foot .app-amount-list {
    margin-left: auto;
}

/*
 * Three figures in a row (the partner's balance: available, on hold, paid out): a panel of three
 * columns stays three until the phone width, where they stack — two and one left over would
 * leave the third figure alone on a second row.
 */
.app-summary--thirds {
    grid-template-columns: repeat(3, minmax(0, 1fr));
}

/*
 * Five figures (the payments page: payments, revenue, refunds, chargebacks, profit): five columns,
 * since four would put the fifth alone on a second row beside an empty stretch of the ground.
 * In the two-column band the odd last part takes the whole row for the same reason (core.md §4.9:
 * the panel stays solid).
 */
.app-summary--fifths {
    grid-template-columns: repeat(5, minmax(0, 1fr));
}

@media (max-width: 1080px) {
    .app-summary:not(.app-summary--thirds) {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .app-summary--fifths > .app-summary__part:last-child:nth-child(odd) {
        grid-column: 1 / -1;
    }
}

/*
 * Only the thirds stack at the phone width: every other panel keeps its two columns down to it
 * (the 1080 px rule above outweighs a bare `.app-summary` one, which is why none is written).
 */
@media (max-width: 640px) {
    .app-summary--thirds {
        grid-template-columns: minmax(0, 1fr);
    }
}

/*
 * Halves.
 *
 * A card holding little data is not stretched across the screen: one word on the left and a
 * row of buttons a thousand pixels away on the right makes the eye track an empty line
 * (core.md §4.2 asks for compactness, §7.1 forbids stretching a form).
 *
 * The same grid serves a single card, which then takes the first of the two columns and so
 * ends up at half width without a rule of its own.
 */
.app-cards--halves {
    grid-template-columns: repeat(2, minmax(0, 1fr));
}

@media (max-width: 1080px) {
    .app-cards--halves {
        grid-template-columns: minmax(0, 1fr);
    }
}

@media (max-width: 1080px) {
    .app-cards--4 {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

@media (max-width: 720px) {
    .app-cards,
    .app-cards--4 {
        grid-template-columns: minmax(0, 1fr);
    }
}

/* --- Card ---------------------------------------------------------------------------- */

/*
 * Cards of one height across a row — but only where there IS a row.
 *
 * `height: 100%` used to sit on `.app-card` itself, and that is a trap rather than a rule. A
 * percentage height resolves against the parent, and it collapses to `auto` only under a parent
 * whose own height is `auto`. A single card standing as a block child of a flex column — and every
 * page of this project is a flex column — gets a parent with a definite height, so the card
 * stretched to the height of the whole page and `.app-card__body { flex: 1 }` filled the difference
 * with nothing. On the planning page that was two thousand pixels of empty card above the grid
 *.
 *
 * So the rule belongs to the containers that lay cards out side by side, where equal heights are
 * the point, and nowhere else. A grid or flex row stretches its items on its own; this is for the
 * card's own children to have something to measure against.
 */
.app-cards > .app-card,
.app-cards--4 > .app-card,
.app-cards--halves > .app-card,
.app-cards--tiles > .app-card {
    height: 100%;
}

.app-card {
    display: flex;
    flex-direction: column;
    overflow: hidden;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface);
}

/*
 * One of several equal cards singled out as the recommended choice: an orange badge at the right
 * of the card head (owner, 23.10.2026: black is oppressive, a badge, orange, on the right).
 * It departs from core.md §4.16 (a frame in the text colour and a flag on the top edge) — the
 * departure is product-kit.md §7. The card itself does not change: no frame, no fill, no shadow,
 * no bigger card — the owner compares equals, and the badge says «this one» without shouting.
 * The badge is the ordinary `app-badge app-badge--warn` inside `app-card__actions--spaced`.
 */

.app-card__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    border-bottom: 1px solid var(--border);
}

.app-card__title {
    font-size: var(--fs-card);
    font-weight: var(--fw-semibold);
    line-height: var(--lh-tight);
}

/*
 * The small capitals above the contents of a big card: «Editor» and «Preview» on the home
 * constructor (the old site's panel title). A label of the card, not a heading of the page, so it
 * is quiet; with `--ruled` a hairline under it separates it from the form below.
 */
.app-card__label {
    margin: 0;
    color: var(--text-3);
    font-family: var(--font-ui);
    font-size: var(--fs-caption);
    font-weight: var(--fw-bold);
    letter-spacing: 0.1em;
    line-height: var(--lh-tight);
    text-transform: uppercase;
}

.app-card__label--ruled {
    padding-bottom: var(--space-2);
    border-bottom: 1px solid var(--border);
}

.app-card__actions {
    display: flex;
    align-items: center;
    flex: none;
    gap: var(--space-0);
}

/* A badge beside a figure or a button in the head: room for each to read on its own. */
.app-card__actions--spaced {
    gap: var(--space-2);
}

/*
 * The badge is taller than the title line (caption size plus its own padding against the card
 * size), so a head with the recommended badge stood a couple of pixels above its neighbour's and the
 * pair no longer lined up. The negative margin takes exactly that difference back, so the head is
 * the height of the title line in both; the badge stays centred by `align-items` of the head.
 */
.app-card__actions--spaced .app-badge {
    margin-block: calc((var(--fs-card) - var(--fs-caption)) * var(--lh-tight) / 2 - var(--inset-badge-y));
}

/* The body takes the slack, so footers of neighbouring cards stay on one line. */
.app-card__body {
    display: flex;
    flex: 1;
    flex-direction: column;
    gap: var(--space-4);
    padding: var(--space-4);
}

.app-card__body--flush {
    padding: 0;
}

/* A picture in a flush body fills the card width and keeps its ratio: the card clips overflow, so the intrinsic width would crop it. */
.app-card__body--flush > img {
    display: block;
    width: 100%;
    height: auto;
}

/*
 * Every footer is one line: it carries the bottom line of its card and nothing else, so the
 * four cards of a row end at the same height without anyone measuring them (core.md §4.3).
 */
.app-card__footer {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-3) var(--space-4);
    border-top: 1px solid var(--border);
    background: var(--bg);
}

/* The label sits left, the figure right, whatever the width of either. */
.app-card__footer .app-amount-list {
    margin-left: auto;
}

/*
 * A card that opens its form in the dialog rather than a page (the bank accounts, map В.Б2 Б3): the name is a
 * button stretched over the card, as the object card's link is (core.md §4.6); the actions of the head are lifted
 * above it, so the delete is a delete and not a way into the form.
 */
.app-card--opens {
    position: relative;
    transition: border-color var(--transition), box-shadow var(--transition);
}

.app-card--opens:hover {
    border-color: var(--accent);
    box-shadow: var(--shadow-card-hover);
}

.app-card--opens .app-card__actions {
    position: relative;
}

.app-card__opener {
    min-width: 0;
    overflow: hidden;
    padding: 0;
    border: 0;
    background: none;
    color: inherit;
    font: inherit;
    font-size: var(--fs-card);
    font-weight: var(--fw-semibold);
    line-height: var(--lh-tight);
    text-align: left;
    text-overflow: ellipsis;
    white-space: nowrap;
    cursor: pointer;
}

/* The whole card answers the touch; the name's own box keeps the touch height as well (core.md §19.1). */
@media (max-width: 720px) {
    .app-card__opener {
        min-height: var(--control-touch);
    }
}

.app-card__opener::after {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: var(--radius);
}

.app-card__opener:focus-visible {
    outline: none;
}

.app-card__opener:focus-visible::after {
    outline: 2px solid var(--accent);
    outline-offset: -2px;
}

/* One fact on one line, cut with an ellipsis and said in full by the tooltip while it is cut (core.md §4.5). */
.app-card__line {
    overflow: hidden;
    font-variant-numeric: var(--numeric);
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* --- Statistics widget --------------------------------------------------------------- */

.app-widget__label {
    color: var(--text-3);
    font-size: var(--fs-caption);
}

.app-widget__value {
    font-size: var(--fs-value);
    font-weight: var(--fw-semibold);
    font-variant-numeric: var(--numeric);
    line-height: var(--lh-tight);
    white-space: nowrap;
}

.app-widget__note {
    color: var(--text-4);
    font-size: var(--fs-caption);
}

/* --- Label and value list ------------------------------------------------------------ */

/*
 * Four tracks, not a flexbox row: the label, then the three cells every amount is made of —
 * the approximation mark, the figure and the currency code (see app\ui\Amount). Each lives
 * in a column of its own, so the figure is always flush against the same edge and the
 * currency code starts at the same x on every row.
 *
 * The count has to match what Amount emits exactly. One track short and the cells wrap onto
 * the next line, which puts a currency code under a label and makes the whole list ripple.
 */
.app-kv {
    display: grid;
    grid-template-columns: 1fr max-content max-content max-content;
    align-items: center;
    gap: var(--inset-row) var(--space-2);
}

/* A list of plain values rather than amounts: two columns, no cells for the currency. */
.app-kv--plain {
    grid-template-columns: 1fr max-content;
}

/* With a trailing glyph after the amount. */
.app-kv--glyph {
    grid-template-columns: 1fr max-content max-content max-content max-content;
}

.app-kv__label {
    color: var(--text-3);
    font-size: var(--fs-caption);
    min-width: 0;
}

/*
 * A second line under a label, quieter than the label itself.
 *
 * For what qualifies the figure rather than names it — when a figure entered by hand was last
 * checked. Without it a copied number looks equally convincing a minute later and half a year
 * later.
 */
.app-kv__hint {
    display: block;
    color: var(--text-disabled);
    font-size: var(--fs-caption);
}

.app-kv__value {
    font-size: var(--fs-text);
    font-weight: var(--fw-semibold);
    font-variant-numeric: var(--numeric);
    text-align: right;
    white-space: nowrap;
}

/* The currency code must not compete with the figure: same column, quieter colour, and the
   spacing comes from the grid gap rather than from a space in the markup. */
.app-kv__currency {
    color: var(--text-3);
    font-size: var(--fs-caption);
    text-align: left;
}

.app-kv__glyph {
    display: flex;
    align-items: center;
    justify-content: center;
}

/* --- Object card, a card that is a link ---------------------------------------------- */

.app-object-card {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    height: 100%;
    /* The anchor inside is stretched over the card, so the card is its containing block. */
    position: relative;
    padding: var(--space-4);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface);
    color: inherit;
    transition: border-color var(--transition), box-shadow var(--transition);
}

.app-object-card:hover {
    border-color: var(--accent);
    box-shadow: var(--shadow-card-hover);
    color: inherit;
    text-decoration: none;
}

/*
 * The whole card leads to the page of its object, and the buttons in the footer
 * do not: the link is stretched over the card by a pseudo-element, and the footer is lifted
 * above it. An anchor wrapped around everything would be invalid markup — a button cannot
 * live inside a link — and would make the text of the card unselectable.
 */
/*
 * The name of the card is not a link in appearance: the whole card is the link, and an
 * underline creeping under the title on hover would say that only the title leads anywhere.
 * The card answers the hover itself, with its border and its shadow.
 */
.app-object-card__link,
.app-object-card__link:hover {
    color: inherit;
    text-decoration: none;
}

.app-object-card__link::after {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: var(--radius);
}

.app-object-card__link:focus-visible::after {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

/* Archived objects come last in any grouping and carry their own colour (rules.md
   §5.8). The muted text stays legible on the muted fill. */
.app-object-card--archived {
    background: var(--archived);
    color: var(--text-4);
}

.app-object-card--archived:hover {
    border-color: var(--border-3);
    box-shadow: none;
}

.app-object-card__head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-2);
}

/*
 * A long name is cut off with an ellipsis and said in full by the tooltip (core.md §4.5).
 *
 * Names longer than the card is wide are the ordinary case. Wrapped, they take a second line
 * and the card carries its figures one line lower than its neighbour: a row of figures that
 * does not line up is read one at a time instead of at a glance.
 *
 * The link inside is not what clips: the stretched `::after` that makes the whole card
 * clickable is positioned against the card, not against this line, so `overflow` here never
 * touches it.
 */
.app-object-card__name {
    overflow: hidden;
    /* The card step of the type scale (core.md §17.8): no size outside the scale. */
    font-size: var(--fs-card);
    font-weight: var(--fw-semibold);
    line-height: var(--lh-tight);
    text-overflow: ellipsis;
    white-space: nowrap;
}

.app-object-card__sub {
    color: var(--text-3);
    font-size: var(--fs-caption);
}

.app-object-card--archived .app-object-card__sub {
    color: inherit;
}

/*
 * The part of a card that is allowed to vary, and the only one.
 *
 * One card has nothing to put here, its neighbour has three badges. The empty space goes above
 * it — margin-top: auto — so what is there sits on the divider below rather than floating in
 * the middle of the card, and everything under that divider stands at one height (core.md §4.5).
 */
.app-object-card__spacer {
    margin-top: auto;
}

.app-object-card__rows {
    padding-top: var(--space-2);
    border-top: 1px solid var(--surface-2);
}

.app-object-card--archived .app-object-card__rows {
    border-top-color: var(--border);
}

/* --- Grouping of object cards -------------------------------------------------------- */

/*
 * Cards are grouped and the group says its name once. A heading per card would repeat the name
 * of the group on every one of them.
 */
.app-group {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.app-group + .app-group {
    margin-top: var(--space-6);
}

.app-group__title {
    font-family: var(--font-ui);
    font-size: var(--fs-section);
    font-weight: var(--fw-semibold);
    color: var(--text-3);
}

/*
 * The line under a section that leads somewhere else.
 *
 * The tail of a list ends with the way to all of it: the link stands under the table, at the
 * edge the eye leaves it by, rather than beside the heading where it would look like an
 * action on the section itself.
 */
.app-group__foot {
    display: flex;
    justify-content: flex-end;
    padding-top: var(--space-3);
}

/* --- One line of a flow: glyph, what it means, the figure ---------------------------- */

/*
 * The glyph, the words and the amount read as one line and are never split across the card
 * (core.md §4.1 forbids the arrow in one corner and the sum in the other).
 */
.app-flow {
    display: grid;
    grid-template-columns: var(--glyph) 1fr max-content max-content max-content;
    align-items: center;
    gap: var(--space-2);
}

.app-flow__glyph--positive {
    color: var(--positive);
}

.app-flow__glyph--negative {
    color: var(--negative);
}

.app-flow__label {
    color: var(--text-3);
    font-size: var(--fs-caption);
}

.app-badges {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-0);
}

/* --- A row of narrow object cards ----------------------------------------------------- */

/*
 * Narrow on purpose: a group can hold eight objects, and two wide cards per row would stretch
 * the page down past anything the owner takes in at once.
 *
 * auto-fill rather than auto-fit: a lone card keeps the width of a card instead of spreading
 * across the whole row.
 */
.app-cards--tiles {
    grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
    gap: var(--space-3);
}

/* Without this the widest line inside a card sets the width of the whole column. */
.app-object-card {
    min-width: 0;
    gap: var(--space-2);
}

/*
 * The comment is context, not content: quiet, small, and clipped rather than wrapping on.
 *
 * The line is kept even when there is no comment. One card with a comment and one without
 * would otherwise carry their balances at two different heights, and a row of balances that
 * does not line up is read figure by figure instead of at a glance (core.md §4.5). What is cut
 * off is said in full by the tooltip.
 */
.app-object-card__note {
    min-height: calc(var(--fs-caption) * var(--lh-tight));
    overflow: hidden;
    color: var(--text-4);
    font-size: var(--fs-caption);
    line-height: var(--lh-tight);
    text-overflow: ellipsis;
    white-space: nowrap;
}

/*
 * Actions sit at the bottom of the card, apart from the figures they act on. Several of them
 * in a narrow card, so the buttons are a size down from the standard one; they still clear the
 * touch target through the pointer-type rule below.
 */
.app-object-card__actions {
    display: flex;
    /* Above the stretched link, so a button is a button and not a way into the page. */
    position: relative;
    /* Money on the left, the card itself on the right; the gap between them is the point. */
    justify-content: space-between;
    gap: var(--space-3);
    padding-top: var(--space-2);
    border-top: 1px solid var(--surface-2);
}

.app-object-card__actions-group {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-0);
}

/* An archived object has fewer actions, and the right-hand group stays where it was. */
.app-object-card__actions-group:last-child {
    margin-left: auto;
}

.app-object-card__actions .app-icon-btn {
    width: var(--control-sm);
    height: var(--control-sm);
}

@media (pointer: coarse) {
    .app-object-card__actions .app-icon-btn {
        width: var(--icon-btn-touch);
        height: var(--icon-btn-touch);
    }
}

.app-object-card--archived .app-object-card__actions {
    border-top-color: var(--border);
}


/*
 * A list of "label — value" pairs: what an object says about itself.
 *
 * A grid rather than a run of pairs, so every value starts at the same place down the column — a
 * value that shifts with the length of its own caption is read one line at a time.
 *
 * Lives with the shell rather than with one page: every kind of object describes itself this way,
 * and a style that belonged to one of them would leave the rest rendering a bare <dl>.
 */
.app-attributes {
    display: grid;
    grid-template-columns: max-content minmax(0, 1fr);
    align-items: baseline;
    gap: var(--space-2) var(--space-4);
    margin: 0;
}

.app-attributes__label {
    color: var(--text-3);
    font-size: var(--fs-caption);
}

.app-attributes__value {
    margin: 0;
    min-width: 0;
}

/*
 * A card as wide as what it holds (core.md §4.2, §4.15; KINV-255).
 *
 * A card is a block and fills its container, so a one-column form (capped at --w-form) or a short table
 * stood inside a card three times as wide as its content. `--form` fits the card to the form: the form's
 * cap plus the body padding and the two borders. `--half` is a table with few rows: half the container, as
 * a form is (--w-form is "half the container, not growing with the monitor"). Both give way on a narrow
 * screen, where `max-width` is simply larger than the viewport and the card takes the whole width.
 */
.app-card--form {
    max-width: calc(var(--w-form) + 2 * var(--space-4) + 2px);
}

.app-card--half {
    max-width: var(--w-form);
}

/*
 * A table of five columns with a link in the last («Document languages») does not fit half the container
 * (the link was cut): two thirds of the page column, the nearest share that holds it (core.md §4.2, «page widths
 * may differ if the difference serves reading»).
 */
.app-card--third2 {
    max-width: calc(var(--w-wide) * 2 / 3);
}
