/* Base typography and the elements pulldown-cmark emits. Loaded on every page.
   Justification and hyphenation need the page to carry lang="…" on <html>. */

:root {
    /* Always light, whatever the system asks; "only" also forbids browsers
       that darken pages on their own, like Chrome on Android, from doing so. */
    color-scheme: only light;

    /* Noto Sans wherever it is installed (Linux, Android, ChromeOS, and
       anywhere the reader added it); otherwise the platform's own UI sans:
       San Francisco through system-ui on Apple platforms, Segoe UI on
       Windows, Roboto on Android. All of these cover Cyrillic. Georgian is
       handled by the :lang(ka) rule below. */
    --font-text: "Noto Sans", system-ui, -apple-system, "Segoe UI", Roboto,
        Cantarell, Ubuntu, "DejaVu Sans", "Helvetica Neue", Arial, sans-serif;
    --font-code: "Noto Sans Mono", ui-monospace, "Cascadia Mono", Menlo,
        Consolas, "DejaVu Sans Mono", "Liberation Mono", monospace;

    /* About 65–70 characters per line at the text size. */
    --measure: 34em;
    --gutter: clamp(1rem, 5vw, 2.5rem);

    --paper: light-dark(#fcfbf8, #1a1a19);
    --ink: light-dark(#1c1c1c, #e3e0da);
    --link: light-dark(#23508f, #9dbfe9);
    --rule: light-dark(#cfcbc4, #43413e);
}

html {
    font-family: var(--font-text);
    /* Phones and narrow windows: the platform's 16px, held steady. */
    font-size: 1rem;
    line-height: 1.5;
    color: var(--ink);
    background: var(--paper);
    -webkit-text-size-adjust: 100%;
    text-size-adjust: 100%;

    /* LaTeX-style block: justified, hyphenated, no short last lines.
       Headings and code opt out below. */
    text-align: justify;
    text-wrap: pretty;
    -webkit-hyphens: auto;
    hyphens: auto;
    hyphenate-limit-chars: 6 3 3;
    overflow-wrap: anywhere;
}

/* Desktop: a larger reading size, 18px at the breakpoint growing to 20px
   on wide screens; a sans has a taller x-height than a book face, so it
   needs a step less. Media queries measure in the browser's default size,
   so 48em is 768px regardless of the rule above. */
@media (min-width: 48em) {
    html {
        font-size: clamp(1.125rem, 1rem + 0.35vw, 1.25rem);
    }

    /* A wider column too: about 85–90 characters per line. Declared on
       :root, since a plain `html` selector loses to the :root block above. */
    :root {
        --measure: 46em;
    }
}

/* Georgian: Noto Sans Georgian is the sibling of the main face and ships
   with Linux, Android and ChromeOS; Segoe UI carries Georgian on Windows
   and DejaVu Sans on older Linux. Latin and Cyrillic mixed into Georgian
   text still use the main stack. */
:lang(ka) {
    font-family: "Noto Sans Georgian", "Segoe UI", "DejaVu Sans", var(--font-text);
}

body {
    margin: 0;
}

/* Paragraphs: no indent, separated by a gap a little under the line height,
   as in a message thread. */
p {
    margin: 0;
}

p + p {
    margin-block-start: 1.2em;
}

h1,
h2,
h3,
h4,
h5,
h6 {
    margin-block: 1.6rem 0.6rem;
    font-weight: bold;
    line-height: 1.2;
    text-align: start;
    text-wrap: balance;
    hyphens: manual;
}

h1 {
    font-size: 1.7em;
}

h2 {
    font-size: 1.35em;
}

h3 {
    font-size: 1.15em;
}

h4,
h5,
h6 {
    font-size: 1em;
}

h5,
h6 {
    font-style: italic;
    font-weight: normal;
}

ul,
ol {
    margin-block: 0.75em;
    padding-inline-start: 1.75em;
}

li + li {
    margin-block-start: 0.25em;
}

li > ul,
li > ol {
    margin-block: 0.25em 0;
}

/* Loose lists wrap items in <p>; keep them tighter than body paragraphs. */
li > p + p {
    margin-block-start: 0.5em;
}

blockquote {
    margin-block: 0.75em;
    margin-inline: 1.5em;
}

/* Tables (the GFM extension): set off from the text by the paragraph gap,
   close under a heading as a paragraph is, with a thin rule under the
   header row. No frame: the only other lines are faint hairlines between
   body rows and between columns, half the rule faded into the paper, with
   room on either side of a column line. Cells are short entries, not body
   copy, so ragged right and, on desktop, unhyphenated; a long word may
   still break, but columns are sized by whole words. Only Markdown tables
   carry no class; the site's own tables keep their page rules.

   A table cannot be narrower than its longest words, column by column, so
   on a phone it could push past the text. Two steps keep it inside: cells
   hyphenate on narrow screens, so the columns can shrink further, and a
   table still too wide scrolls sideways within the measure. The renderer
   emits a bare <table>, so the table is its own scrolling box: a block as
   wide as its content and no wider than the text, the rows laid out inside
   it as before. */
table:not([class]) {
    --table-hairline: color-mix(in oklab, var(--rule) 50%, var(--paper));
    display: block;
    inline-size: max-content;
    max-inline-size: 100%;
    overflow-x: auto;
    margin-block: 1.2em;
    border-collapse: collapse;
}

:is(h1, h2, h3, h4, h5, h6) + table:not([class]) {
    margin-block-start: 0;
}

table:not([class]) :is(th, td) {
    padding-block: 0.25em;
    padding-inline: 0.75em;
    text-align: start;
    vertical-align: top;
    overflow-wrap: break-word;
}

@media (min-width: 48em) {
    table:not([class]) :is(th, td) {
        hyphens: manual;
    }
}

table:not([class]) :is(th, td):first-child {
    padding-inline-start: 0;
}

table:not([class]) :is(th, td):last-child {
    padding-inline-end: 0;
}

table:not([class]) :is(th, td) + :is(th, td) {
    border-inline-start: 1px solid var(--table-hairline);
}

table:not([class]) tbody tr + tr > td {
    border-block-start: 1px solid var(--table-hairline);
}

table:not([class]) th {
    border-block-end: 1px solid var(--rule);
}

code,
pre {
    font-family: var(--font-code);
    font-size: 0.875em;
    hyphens: none;
}

pre {
    margin-block: 0.75em;
    line-height: 1.35;
    text-align: start;
    white-space: pre;
    overflow-x: auto;
}

pre code {
    font-size: 1em;
}

hr {
    inline-size: 40%;
    margin-block: 1.5em;
    margin-inline: auto;
    border: 0;
    border-block-start: 1px solid var(--rule);
}

/* Images in running text: cap height, sitting on the baseline, so a
   wordmark reads as a word of the sentence. The em fallback approximates
   the cap height of the book faces above for browsers without `cap`. */
img {
    display: inline;
    block-size: 0.7em;
    block-size: 1cap;
    inline-size: auto;
    vertical-align: baseline;
    /* Artwork usually has no side bearing of its own. */
    margin-inline-start: 0.08em;
}

/* Displayed images: a paragraph that contains nothing but one image.
   The renderer emits these as <figure><img></figure>, and the image is
   scaled to the width of the text. */
figure {
    margin-block: 1.5em;
    margin-inline: 0;
}

figure > img {
    display: block;
    inline-size: 100%;
    block-size: auto;
    margin-inline: 0;
}

/* Links: coloured ink with a thin, muted underline that fills in on hover. */
a {
    color: var(--link);
    text-decoration-line: underline;
    text-decoration-thickness: 0.06em;
    text-decoration-color: color-mix(in oklab, currentColor 40%, transparent);
    text-underline-offset: 0.16em;
    text-decoration-skip-ink: auto;
}

a:hover {
    text-decoration-color: currentColor;
}

a:focus-visible {
    outline: 2px solid var(--link);
    outline-offset: 2px;
    border-radius: 2px;
}

/* Footnotes (the GFM extension). The reference is a superscript number, so
   the link colour alone marks it; an underline under a raised digit is noise. */
.footnote-reference > a {
    text-decoration-line: none;
}

/* A definition reads "1. Note" on one line: pulldown-cmark emits the label
   as a <sup> followed by the note's first paragraph as a block, so the label
   is set on the baseline and that paragraph runs in after it. */
.footnote-definition-label {
    font-size: inherit;
    vertical-align: baseline;
}

.footnote-definition-label::after {
    content: ". ";
}

.footnote-definition-label + p {
    display: inline;
}
/* The page header: <header> holding the site's Markdown header in
   <a class="masthead">, a link to the main page, followed by the language
   switch in <nav class="languages">, then the link to the news page in
   <a class="feed">, named for the feed icon it holds as an <img>, and the
   link back to the top in <a class="to-top"> at the end of <body>. Each
   language in the switch carries its flag in <span class="flag"> and its
   name, in itself, in <span class="language-name">. Loaded on every page
   but the root index. Requires markdown.css.

   Always one line: the masthead on the left, the switch and the feed on
   the right, all three centred on one another. The names are there for
   Windows, which draws no flags; the switch shows them only on windows
   wide enough for the masthead, the named switch and the feed side by
   side, and flags alone below that. On phones even the flags leave the
   masthead too little room at its full size, so it scales down with the
   screen instead of breaking. The header stays pinned to the top of the
   window, on phones as on the desktop, so the way to the main page is
   always at hand.

   The widths are sized for the longest masthead, the English one with its
   wide logo, with some room to spare; a longer masthead needs them
   revisited. */

body > header {
    display: flex;
    /* The three differ in size, so no baseline serves them all, and the
       icon has none of its own. */
    align-items: center;
    justify-content: space-between;
    gap: 0.75em;
    max-inline-size: var(--measure);
    margin-inline: auto;
    padding-block: 1.25rem 0.75rem;
    padding-inline: var(--gutter);
    border-block-end: 1px solid var(--rule);

    /* Pinned to the top while the page scrolls beneath it. The paper
       background keeps passing text from showing through. */
    position: sticky;
    inset-block-start: 0;
    z-index: 1;
    background: var(--paper);

    /* Short running text, not body copy: no justification, no paragraph
       indent, ragged right. */
    text-align: start;
    hyphens: manual;
}

/* A title, not body copy: the second heading size, set tighter. On phones
   it gives up size to keep the line whole: 8vw less 0.9em is what is left
   of the screen beside the flags and the feed, over the masthead's length,
   with a margin. Wider screens reach the full size. */
.masthead {
    flex: 1 1 auto;
    min-inline-size: 0;
    font-size: clamp(0.75em, 8vw - 0.9em, 1.35em);
    line-height: 1.3;
}

.masthead > :first-child {
    margin-block-start: 0;
}

.masthead p + p {
    margin-block-start: 0.5em;
}

/* The masthead links to the main page but reads as the title: set in the
   text colour, never underlined. The focus ring comes from markdown.css. */
a.masthead {
    color: var(--ink);
    text-decoration-line: none;
}

/* Language switch: a single row that never shrinks nor wraps, a large flag
   per language. The current language is set in the text colour with a rule
   beneath it; the others take the link colour and only underline their
   names on hover. */
nav.languages {
    flex: 0 0 auto;
}

nav.languages > ul {
    display: flex;
    flex-wrap: nowrap;
    gap: 0.4em;
    margin: 0;
    padding: 0;
    list-style: none;
    font-size: 0.9em;
}

nav.languages li {
    white-space: nowrap;
}

nav.languages li + li {
    margin-block-start: 0;
}

nav.languages a,
nav.languages .selected {
    display: inline-flex;
    align-items: center;
    padding-block: 0.1em;
    border-block-end: 0.12em solid transparent;
}

nav.languages a {
    text-decoration-line: none;
}

nav.languages a:hover {
    text-decoration-line: underline;
}

nav.languages .selected {
    color: var(--ink);
    border-block-end-color: currentColor;
}

/* Flags are colour glyphs; keep them from tinting like the link. A unit
   line height keeps the larger glyph from pushing the row taller. */
nav.languages .flag {
    font-size: 1.3em;
    line-height: 1;
    font-style: normal;
    text-decoration: none;
}

/* Flags alone: the name is kept for screen readers, the flag being hidden
   from them, and only taken out of sight. */
nav.languages .language-name {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
}

/* The feed: the link to the news page, its icon alone, at the switch's
   size, about the height of the flags, centred on the line like them. */
a.feed {
    flex: 0 0 auto;
    font-size: 0.9em;
    line-height: 1;
}

a.feed > img {
    display: block;
    block-size: 1.2em;
    margin-inline-start: 0;
}

/* Centred boxes are not centred glyphs: the flags and the icon read low
   beside the letters around them, so both are raised by the same amount,
   taken in the header's size, without moving anything else, the names
   included. */
nav.languages .flag,
a.feed {
    position: relative;
    inset-block-start: -0.12rem;
}

/* Back to the top: <a class="to-top">, after the page's content, an arrow
   up to a bar, its name for screen readers in its label. A light grey disc
   ringed in the text colour, pinned to the window's bottom right corner,
   opaque so passing text does not show through. A button rather than a
   link: the arrow centred in the text colour, never underlined, the grey
   deepening on hover. Sized in rem, the same on every page, and large
   enough to tap on phones. */
a.to-top {
    position: fixed;
    inset-block-end: 1rem;
    inset-inline-end: 1rem;
    z-index: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    box-sizing: border-box;
    inline-size: 2.75rem;
    block-size: 2.75rem;
    border: 2px solid var(--ink);
    border-radius: 50%;
    background: color-mix(in oklab, var(--ink) 10%, var(--paper));
    color: var(--ink);
    font-size: 1.25rem;
    line-height: 1;
    text-decoration-line: none;
}

a.to-top:hover {
    background: color-mix(in oklab, var(--ink) 18%, var(--paper));
}

/* At the top of the page there is nowhere to go back to, so the button is
   out of sight there, nor reachable by the keyboard, and fades in over the
   first 8rem of scrolling, about five lines. The fade follows the page's scroll position
   rather than time. A page too short to scroll has no scroll timeline, and
   the button stays hidden. Browsers without scroll timelines keep it always
   visible. */
@supports (animation-timeline: scroll()) {
    a.to-top {
        visibility: hidden;
        opacity: 0;
        animation: to-top-reveal linear both;
        animation-timeline: scroll();
        animation-range: 0 8rem;
    }
}

@keyframes to-top-reveal {
    from {
        visibility: hidden;
        opacity: 0;
    }

    to {
        visibility: visible;
        opacity: 1;
    }
}

/* Names beside the flags, only once the masthead fits beside the whole
   named switch and the feed, at the text column's full width. */
@media (min-width: 57em) {
    body > header {
        gap: 1.5em;
    }

    /* The feed follows the switch closer than the switch follows the
       masthead, the two reading as one group. */
    a.feed {
        margin-inline-start: -0.75em;
    }

    nav.languages > ul {
        gap: 1em;
    }

    nav.languages .flag {
        margin-inline-end: 0.35em;
    }

    nav.languages .language-name {
        position: static;
        inline-size: auto;
        block-size: auto;
        margin: 0;
        overflow: visible;
        clip-path: none;
    }
}
/* A person page: <article class="person"> holding, when the page is a
   translation, the banner in <p class="banner">, then the name in <h1>,
   the Markdown description in <div class="description">, the Markdown
   biography in <section class="biography"> and, when present, contact
   details in <ul class="contacts">. Requires markdown.css and
   banner.css. */

article.person {
    max-inline-size: var(--measure);
    margin-inline: auto;
    padding-block: clamp(2rem, 8vh, 5rem) clamp(3rem, 10vh, 6rem);
    padding-inline: var(--gutter);
}

/* Set like a LaTeX title: large, regular weight, centred. */
article.person > h1 {
    margin-block: 0;
    font-size: 2em;
    font-weight: normal;
    text-align: center;
}

/* The words standing for a family name nobody knows, "(surname unknown)",
   shown in the title and, in email.css, in an email's headers. They are
   no part of the name, so
   they drop well below its size, to little more than body text, in a
   lighter ink, and stay upright, italics being no mark of a stand-in on
   the Russian page. Sitting on the name's baseline, the smaller words
   would look sunk beside it, so they are raised by half the difference
   between the two cap heights, centring them on the name. In the words'
   own font, the name's cap height is their 1cap over their size ratio. */
article.person > h1 .unknown-name {
    font-size: 0.65em;
    vertical-align: calc((1 / 0.65 - 1) * 0.5cap);
    color: color-mix(in oklab, currentColor 70%, var(--paper));
}

/* The subtitle under the title: a little larger than body text, italic,
   centred and set like the heading, in a slightly lighter ink. */
article.person > .description {
    margin-block-start: 0.5rem;
    font-size: 1.15em;
    font-style: italic;
    text-align: center;
    text-wrap: balance;
    hyphens: manual;
    color: color-mix(in oklab, var(--ink) 75%, var(--paper));
}

article.person > .description > :first-child {
    margin-block-start: 0;
}

article.person > .biography {
    margin-block-start: 2rem;
}

article.person > .biography > :first-child {
    margin-block-start: 0;
}

/* Contact details close the article like a signature block: a short rule
   as after a Markdown <hr>, then one centred line per item, each a glyph
   followed by the address as plain text (never a mailto: link, since the
   site must not invite contact), a little smaller than body text. Only
   the LinkedIn item is a link. */
article.person > .contacts {
    margin-block: 2.5rem 0;
    padding: 0;
    list-style: none;
    font-size: 0.9em;
    text-align: center;
    hyphens: manual;
}

article.person > .contacts::before {
    content: "";
    display: block;
    inline-size: 40%;
    margin-block-end: 1.5em;
    margin-inline: auto;
    border-block-start: 1px solid var(--rule);
}

/* Each item is a centred row of glyph and text. The symbol glyphs sit
   at different heights in different platform fonts, so they are centred
   on the text rather than trusting their baselines. */
article.person > .contacts > li {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.4rem;
}

/* The LinkedIn stand-in is ordinary text, so it shares the baseline. */
article.person > .contacts > .linkedin {
    align-items: baseline;
}

/* Glyphs sit in a fixed slot so the items line up beneath one another.
   They are plain text glyphs in the ink colour. Twice the item text size,
   with a unit line height so the slot is no taller than the glyph itself. */
article.person > .contacts .icon {
    inline-size: 1.1em;
    font-size: 2em;
    line-height: 1;
    text-align: end;
    color: var(--ink);
}

/* The symbol fonts draw this glyph low in its box, so centring the box
   leaves the ink hanging below the text. Lift it by eye; the value is
   in the glyph's own em, so 0.1em is a fifth of the text size. */
article.person > .contacts > .email > .icon {
    translate: 0 -0.1em;
}

/* No LinkedIn glyph exists; the wordmark's "in" is set bold and sans,
   only a little larger than the text since its capitals are already tall. */
article.person > .contacts > .linkedin > .icon {
    font-family: system-ui, sans-serif;
    font-weight: bold;
    font-size: 1.1em;
}

/* The persons page: <article class="persons"> holding the title in <h1>,
   the Markdown introduction in <div class="text"> and one row per person
   in <table class="list">: the linked name, then the description. Laid
   out like the emails page, with the name in the date's place. */

article.persons {
    max-inline-size: var(--measure);
    margin-inline: auto;
    padding-block: clamp(2rem, 8vh, 5rem) clamp(3rem, 10vh, 6rem);
    padding-inline: var(--gutter);
}

/* Set like a LaTeX title, as on the person page. */
article.persons > h1 {
    margin-block: 0;
    font-size: 2em;
    font-weight: normal;
    text-align: center;
}

article.persons > .text {
    margin-block-start: 2rem;
}

article.persons > .text > :first-child {
    margin-block-start: 0;
}

/* The list, on a phone: a name kept on one line beside the description
   would leave the description a sliver, so each person is a short block,
   the name above and the description under it as its subtitle, set as
   on the person page: italic, in a lighter ink and here a little smaller
   than the name, a blank line between persons. */
article.persons > .list,
article.persons > .list > tbody,
article.persons > .list tr,
article.persons > .list td {
    display: block;
}

article.persons > .list {
    margin-block-start: 2rem;
    text-align: start;
}

article.persons > .list tr + tr {
    margin-block-start: 1em;
}

article.persons > .list td {
    padding: 0;
}

article.persons > .list .description {
    margin-block-start: 0.15em;
    font-size: 0.9em;
    font-style: italic;
    color: color-mix(in oklab, var(--ink) 75%, var(--paper));
}

/* Desktop: an open table with no rules, a blank line between rows and
   two words of space between columns, more open than the emails list
   since both cells here are prose. The description takes whatever width
   the name leaves, so it is the only column that wraps, and is set as
   the name is. The name is a margin note beside it: kept on one line so
   the descriptions align down a single column, and centred on the row so
   it sits beside the middle of a description that runs to several lines. */
@media (min-width: 48em) {
    article.persons > .list {
        display: table;
        inline-size: 100%;
        border-collapse: collapse;
    }

    article.persons > .list > tbody {
        display: table-row-group;
    }

    article.persons > .list tr {
        display: table-row;
    }

    article.persons > .list td {
        display: table-cell;
        vertical-align: baseline;
    }

    article.persons > .list tr + tr > td {
        padding-block-start: 1em;
    }

    article.persons > .list td + td {
        padding-inline-start: 2em;
    }

    article.persons > .list .name {
        vertical-align: middle;
        white-space: nowrap;
    }

    article.persons > .list .description {
        inline-size: 100%;
        margin-block-start: 0;
        font-size: inherit;
        font-style: inherit;
        color: inherit;
    }
}

/* The description is Markdown, so it arrives wrapped in <p>; inside a
   table cell those paragraphs carry no outer margin. */
article.persons > .list .description > :first-child {
    margin-block-start: 0;
}

article.persons > .list .description > :last-child {
    margin-block-end: 0;
}
/* An entity page: <article class="entity"> holding, when the page is a
   translation, the banner in <p class="banner">, then the name in <h1>,
   the Markdown description in <div class="description">, the link to the
   entity's own site in <p class="website">, the Markdown record in
   <section class="record"> and, when it has any, the staff in
   <section class="staff">: a heading in <h2> and one row per member in
   <table class="list">, the linked name then the role.
   Requires markdown.css and banner.css. */

article.entity {
    max-inline-size: var(--measure);
    margin-inline: auto;
    padding-block: clamp(2rem, 8vh, 5rem) clamp(3rem, 10vh, 6rem);
    padding-inline: var(--gutter);
}

/* Set like a LaTeX title, as on the person page. */
article.entity > h1 {
    margin-block: 0;
    font-size: 2em;
    font-weight: normal;
    text-align: center;
}

/* The subtitle under the title, as on the person page. */
article.entity > .description {
    margin-block-start: 0.5rem;
    font-size: 1.15em;
    font-style: italic;
    text-align: center;
    text-wrap: balance;
    hyphens: manual;
    color: color-mix(in oklab, var(--ink) 75%, var(--paper));
}

article.entity > .description > :first-child {
    margin-block-start: 0;
}

/* The website: a short centred line beneath the subtitle in the smaller
   size and lighter ink of the site's asides, as the email page sets the
   links to its originals. The link itself keeps the link colour, and the
   address stays whole rather than breaking at a slash. */
article.entity > .website {
    margin-block-start: 1em;
    font-size: 0.9em;
    text-align: center;
    hyphens: manual;
    color: color-mix(in oklab, var(--ink) 75%, var(--paper));
}

article.entity > .website > a {
    white-space: nowrap;
}

/* The record is the body of the page, as the biography is on the person
   page. */
article.entity > .record {
    margin-block-start: 2rem;
}

article.entity > .record > :first-child {
    margin-block-start: 0;
}

/* The staff close the article: a section heading, then the list. */
article.entity > .staff {
    margin-block-start: 2rem;
}

article.entity > .staff > h2 {
    margin-block-start: 0;
}

/* The list: an open table with no rules, a blank line between rows and
   two words of space between columns, as on the persons page. The role
   takes whatever width the name leaves, so it is the only column that
   wraps. */
article.entity > .staff > .list {
    inline-size: 100%;
    border-collapse: collapse;
    text-align: start;
}

article.entity > .staff > .list td {
    padding: 0;
    vertical-align: baseline;
}

article.entity > .staff > .list tr + tr > td {
    padding-block-start: 1em;
}

article.entity > .staff > .list td + td {
    padding-inline-start: 2em;
}

/* The name is a margin note beside the role: kept on one line so the
   roles align down a single column, and centred on the row so it sits
   beside the middle of a role that runs to several lines. */
article.entity > .staff > .list .name {
    vertical-align: middle;
    white-space: nowrap;
}

article.entity > .staff > .list .role {
    inline-size: 100%;
}

/* The entities page: <article class="entities"> holding the title in
   <h1>, the Markdown introduction in <div class="text"> and one row per
   entity in <table class="list">: the linked name, then the description.
   Laid out like the persons page. */

article.entities {
    max-inline-size: var(--measure);
    margin-inline: auto;
    padding-block: clamp(2rem, 8vh, 5rem) clamp(3rem, 10vh, 6rem);
    padding-inline: var(--gutter);
}

/* Set like a LaTeX title, as on the person page. */
article.entities > h1 {
    margin-block: 0;
    font-size: 2em;
    font-weight: normal;
    text-align: center;
}

article.entities > .text {
    margin-block-start: 2rem;
}

article.entities > .text > :first-child {
    margin-block-start: 0;
}

/* The list: an open table with no rules, a blank line between rows and
   two words of space between columns, as on the persons page. The
   description takes whatever width the name leaves, so it is the only
   column that wraps. */
article.entities > .list {
    inline-size: 100%;
    margin-block-start: 2rem;
    border-collapse: collapse;
    text-align: start;
}

article.entities > .list td {
    padding: 0;
    vertical-align: baseline;
}

article.entities > .list tr + tr > td {
    padding-block-start: 1em;
}

article.entities > .list td + td {
    padding-inline-start: 2em;
}

/* The name is a margin note beside the description: kept on one line so
   the descriptions align down a single column, and centred on the row so
   it sits beside the middle of a description that runs to several lines. */
article.entities > .list .name {
    vertical-align: middle;
    white-space: nowrap;
}

article.entities > .list .description {
    inline-size: 100%;
}

/* The description is Markdown, so it arrives wrapped in <p>; inside a
   table cell those paragraphs carry no outer margin. */
article.entities > .list .description > :first-child {
    margin-block-start: 0;
}

article.entities > .list .description > :last-child {
    margin-block-end: 0;
}
/* An estate page: <article class="estate"> holding, when the page is a
   translation, the banner in <p class="banner">, then the name in <h1>,
   the Markdown record in <section class="record"> and the address in
   <p class="address">. Laid out like the person page, with the address
   in the contacts' place and no subtitle. Requires markdown.css and
   banner.css. */

article.estate {
    max-inline-size: var(--measure);
    margin-inline: auto;
    padding-block: clamp(2rem, 8vh, 5rem) clamp(3rem, 10vh, 6rem);
    padding-inline: var(--gutter);
}

/* Set like a LaTeX title, as on the person page. */
article.estate > h1 {
    margin-block: 0;
    font-size: 2em;
    font-weight: normal;
    text-align: center;
}

/* The record is the body of the page, as on the entity page. */
article.estate > .record {
    margin-block-start: 2rem;
}

article.estate > .record > :first-child {
    margin-block-start: 0;
}

/* The address closes the article like the contacts on the person page: a
   short rule as after a Markdown <hr>, then a block a little smaller than
   body text, set flush with the record above rather than centred. Plain
   text, never a link. The address is short and its parts are proper
   names, so no hyphenation. */
article.estate > .address {
    margin-block: 2.5rem 0;
    font-size: 0.9em;
    text-align: start;
    hyphens: manual;
}

article.estate > .address::before {
    content: "";
    display: block;
    inline-size: 40%;
    margin-block-end: 1.5em;
    margin-inline: auto;
    border-block-start: 1px solid var(--rule);
}

/* The label takes a line of its own above the address. */
article.estate > .address > .label {
    display: block;
}

/* The address text keeps the line breaks of its source, so a postal
   address set over several lines in the TOML reads as such here, each
   line centred. Runs of spaces still collapse. */
article.estate > .address > .value {
    white-space: pre-line;
}

/* The estates page: <article class="estates"> holding the title in <h1>,
   the Markdown introduction in <div class="text"> and one item per
   estate in <ul class="list">: the linked name alone, so a plain list
   rather than the two-column table of the entities page. */

article.estates {
    max-inline-size: var(--measure);
    margin-inline: auto;
    padding-block: clamp(2rem, 8vh, 5rem) clamp(3rem, 10vh, 6rem);
    padding-inline: var(--gutter);
}

/* Set like a LaTeX title, as on the person page. */
article.estates > h1 {
    margin-block: 0;
    font-size: 2em;
    font-weight: normal;
    text-align: center;
}

article.estates > .text {
    margin-block-start: 2rem;
}

article.estates > .text > :first-child {
    margin-block-start: 0;
}

/* The list: a plain stack of names, no markers, a blank line between
   items as between the rows of the entities list. Names, not body copy,
   so ragged right and no hyphenation. */
article.estates > .list {
    margin-block: 2rem 0;
    padding: 0;
    list-style: none;
    text-align: start;
    hyphens: manual;
}

article.estates > .list > li + li {
    margin-block-start: 1em;
}
/* An email page: <article class="email"> holding, when the page is a
   translation, the banner in <p class="banner">, then the SHA-256 of the
   EML in <p class="hash"> (its label in <span class="label">, the digest in
   <code>); then <nav class="thread">, in which the buttons to the previous
   and next email in the thread, <a class="previous"> and <a class="next">
   (each present only when the email has one), stand around the link to
   the list of emails, <a class="all">; then the header fields in
   <table class="headers"> (one <tr> per field, the label in <th>, a mailbox's owner as the site's
   <a class="person"> link, the date closed by "(UTC)" in
   <span class="zone">, the subject last), then the Markdown body in
   <section class="body">. Requires markdown.css and banner.css. */

/* The page starts just under the header's rule, as far below it as the
   header's text stands above it, since the hash sits at the very top; the
   gap other pages open with comes after the hash instead. Under a banner
   the hash comes after the banner's gap, as any page's opening does. */
article.email {
    max-inline-size: var(--measure);
    margin-inline: auto;
    padding-block: 0.75rem clamp(3rem, 10vh, 6rem);
    padding-inline: var(--gutter);
}

/* The hash opens the page: its label on one line and the digest on the
   next, centred, in the smaller size and lighter ink of the site's
   asides, since it is there to be checked rather than read. The email
   begins below it after the page's usual opening gap. The hash is the
   same in every language, so it is set in the same faces in every
   language too, overriding the Georgian stack of markdown.css, lest it
   seem to change when the reader switches language. */
article.email > .hash {
    margin-block-end: clamp(2rem, 8vh, 5rem);
    font-family: var(--font-text);
    font-size: 0.9em;
    text-align: center;
    hyphens: manual;
    color: color-mix(in oklab, var(--ink) 75%, var(--paper));
}

/* The digest is set small, so its 64 digits keep to one line on a desktop.
   It has no word to break at, so on a screen too narrow for that it wraps
   between any two digits. */
article.email > .hash > code {
    display: block;
    font-family: var(--font-code);
    font-size: 0.75em;
    word-break: break-all;
}

/* The row above the headers, in the same smaller size as the hash: the
   three buttons share one row, the outer columns equal, so the link to
   the list stays centred on the page whether the email has two
   neighbours, one or none. */
article.email > .thread {
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    column-gap: 1em;
    align-items: baseline;
    margin-block-end: 1em;
    font-size: 0.9em;
    hyphens: manual;
}

article.email > .thread > .previous {
    grid-area: 1 / 1;
    justify-self: start;
}

article.email > .thread > .all {
    grid-area: 1 / 2;
}

article.email > .thread > .next {
    grid-area: 1 / 3;
    justify-self: end;
}

/* The buttons: the link set in a rounded hairline frame in the link's own
   colour, on one line, underlined only on hover, as the button on the
   chats page. */
article.email > .thread > .previous,
article.email > .thread > .all,
article.email > .thread > .next {
    padding-block: 0.15em;
    padding-inline: 0.7em;
    border: 1px solid color-mix(in oklab, currentColor 50%, transparent);
    border-radius: 0.5em;
    white-space: nowrap;
    text-decoration-line: none;
}

article.email > .thread > .previous:hover,
article.email > .thread > .all:hover,
article.email > .thread > .next:hover {
    text-decoration-line: underline;
}

/* The header fields are set like the opening of a letter: a quiet
   two-column list, ragged right, the labels in bold. Browsers insert
   <tbody>, so the rows are matched as descendants, not children. */
article.email > .headers {
    max-inline-size: 100%;
    margin: 0;
    border-collapse: collapse;
    font-size: 0.95em;
    text-align: start;
    hyphens: manual;
}

article.email > .headers th,
article.email > .headers td {
    padding: 0;
    vertical-align: baseline;
}

article.email > .headers tr + tr > * {
    padding-block-start: 0.2em;
}

/* Labels: the first column, bold, kept on one line and clear of the values. */
article.email > .headers th {
    padding-inline-end: 1em;
    font-weight: bold;
    text-align: start;
    white-space: nowrap;
}

/* Addresses are monospace through <code> and may wrap anywhere on a
   narrow screen; the global overflow-wrap already allows that. Keep the
   owner's name whole, since it is short and reads as one word. */
article.email > .headers .person {
    white-space: nowrap;
}

/* The words standing for a family name nobody knows, "(surname unknown)",
   are no part of the name, so they are set a little smaller in a lighter
   shade of the link's ink, as in the person page's title, and stay upright
   for the same reason. As there, they are raised to centre on the name. */
article.email > .headers .person .unknown-name {
    font-size: 0.85em;
    vertical-align: calc((1 / 0.85 - 1) * 0.5cap);
    color: color-mix(in oklab, currentColor 70%, var(--paper));
}

/* The time zone after the date, "(UTC)", is there for accuracy rather
   than to be read, so it is set quietly: in small capitals, in the
   lighter ink of the site's asides. */
article.email > .headers .zone {
    font-variant-caps: all-small-caps;
    color: color-mix(in oklab, var(--ink) 75%, var(--paper));
}

/* The body stands a blank line and a half below the header. */
article.email > .headers + * {
    margin-block-start: 1.5em;
}

/* The body's blocks take their spacing from markdown.css. Whatever it
   opens with, a paragraph, a heading or a list, sits flush against the
   gap above, and its last block adds nothing to the article's padding. */
article.email > .body > :first-child {
    margin-block-start: 0;
}

article.email > .body > :last-child {
    margin-block-end: 0;
}

/* Where a link lands on an anchor in the email: its top a little above the
   middle of the screen, so the passage reads with what leads up to it, and
   never less than clear of the pinned header, on a short window. */
article.email [id] {
    scroll-margin-block-start: max(6rem, 40svh);
}

/* The block of the body a link landed on, whether the anchor is the
   block itself or a few words inside it: tinted with the link colour, so
   the eye finds it at once. The tint spills a little past the text
   through the shadow, which takes no room, so nothing around it moves. */
article.email > .body > :is(:target, :has(:target)) {
    --highlight: color-mix(in oklab, var(--link) 7%, var(--paper));

    border-radius: 0.2em;
    background: var(--highlight);
    box-shadow: 0 0 0 0.4em var(--highlight);
}

/* The emails page: <article class="emails"> holding the title in <h1>,
   the Markdown introduction in <div class="text"> and one row per email
   in <table class="list">: the date in <td class="date">, the Markdown
   description in <td class="description"> and, in <td class="email">, the
   button to the email page. */

article.emails {
    max-inline-size: var(--measure);
    margin-inline: auto;
    padding-block: clamp(2rem, 8vh, 5rem) clamp(3rem, 10vh, 6rem);
    padding-inline: var(--gutter);
}

/* Set like a LaTeX title, as on the person page. */
article.emails > h1 {
    margin-block: 0;
    font-size: 2em;
    font-weight: normal;
    text-align: center;
}

article.emails > .text {
    margin-block-start: 2rem;
}

article.emails > .text > :first-child {
    margin-block-start: 0;
}

/* The list, on a phone: three columns would leave the description a
   sliver, so each email is a grid of two rows, the date alone above and
   the description beside the button below, with a line of space between
   emails, as room for the buttons' frames. The description takes
   whatever width the button leaves, so it is the only part that wraps,
   and the button is centred on it. */
article.emails > .list,
article.emails > .list > tbody {
    display: block;
}

article.emails > .list {
    margin-block-start: 2rem;
    text-align: start;
}

article.emails > .list tr {
    display: grid;
    grid-template-columns: 1fr auto;
    column-gap: 1.5em;
    align-items: center;
}

article.emails > .list tr + tr {
    margin-block-start: 1em;
}

article.emails > .list td {
    padding: 0;
}

/* The date is a note on the description: kept on one line, in the
   lighter ink of the site's asides, with tabular figures so the dates
   line up. On a phone it spans the row above the description. */
article.emails > .list .date {
    grid-column: 1 / -1;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
    color: color-mix(in oklab, var(--ink) 75%, var(--paper));
}

/* Desktop: an open table with no rules, the date a margin note beside
   the description, a line of space between rows and a word of space
   between columns, as the chats list, with the button's room before
   it. */
@media (min-width: 48em) {
    article.emails > .list {
        display: table;
        inline-size: 100%;
        border-collapse: collapse;
    }

    article.emails > .list > tbody {
        display: table-row-group;
    }

    article.emails > .list tr {
        display: table-row;
    }

    article.emails > .list td {
        vertical-align: baseline;
    }

    article.emails > .list tr + tr > td {
        padding-block-start: 1em;
    }

    article.emails > .list td + td {
        padding-inline-start: 1em;
    }

    article.emails > .list .description {
        inline-size: 100%;
    }

    article.emails > .list .email {
        padding-inline-start: 1.5em;
        vertical-align: middle;
    }
}

/* The button, as on the chats page: the link set in a rounded hairline
   frame in the link's own colour, on one line, closing the row at the
   right and centred on a description that runs to several lines.
   Underlined only on hover, since the frame already marks it a link. */
article.emails > .list .email {
    text-align: end;
    white-space: nowrap;
}

article.emails > .list .email > a {
    display: inline-block;
    padding-block: 0.15em;
    padding-inline: 0.7em;
    border: 1px solid color-mix(in oklab, currentColor 50%, transparent);
    border-radius: 0.5em;
    text-decoration-line: none;
}

article.emails > .list .email > a:hover {
    text-decoration-line: underline;
}
/* A document page: <article class="document"> holding, when the text is
   a translation, the banner in <p class="banner">, its "from the original" linking
   to the original file, then the title in <h1>, the Markdown description
   in <div class="description">, the link to the original file in
   <p class="original"> and the Markdown text in <section class="text">.
   Laid out like the entity page, with the original in the website's
   place. Requires markdown.css and banner.css. */

article.document {
    max-inline-size: var(--measure);
    margin-inline: auto;
    padding-block: clamp(2rem, 8vh, 5rem) clamp(3rem, 10vh, 6rem);
    padding-inline: var(--gutter);
}

/* Set like a LaTeX title, as on the person page. */
article.document > h1 {
    margin-block: 0;
    font-size: 2em;
    font-weight: normal;
    text-align: center;
}

/* The subtitle under the title, as on the person page. */
article.document > .description {
    margin-block-start: 0.5rem;
    font-size: 1.15em;
    font-style: italic;
    text-align: center;
    text-wrap: balance;
    hyphens: manual;
    color: color-mix(in oklab, var(--ink) 75%, var(--paper));
}

article.document > .description > :first-child {
    margin-block-start: 0;
}

/* The original: a short centred line beneath the subtitle in the smaller
   size and lighter ink of the site's asides, as the email page sets the
   links to its originals. The link itself keeps the link colour. */
article.document > .original {
    margin-block-start: 1em;
    font-size: 0.9em;
    text-align: center;
    hyphens: manual;
    color: color-mix(in oklab, var(--ink) 75%, var(--paper));
}

/* The text is the body of the page, as the record is on the entity page. */
article.document > .text {
    margin-block-start: 2rem;
}

article.document > .text > :first-child {
    margin-block-start: 0;
}

/* Where a link lands on an anchor in the document: its top a little above
   the middle of the screen, so the passage reads with what leads up to it,
   and never less than clear of the pinned header, on a short window, as on
   the email page. */
article.document [id] {
    scroll-margin-block-start: max(6rem, 40svh);
}

/* The block of the text a link landed on, whether the anchor is the block
   itself or a few words inside it: tinted with the link colour, so the eye
   finds it at once, as on the email page. The tint spills a little past
   the text through the shadow, which takes no room, so nothing around it
   moves. */
article.document > .text > :is(:target, :has(:target)) {
    --highlight: color-mix(in oklab, var(--link) 7%, var(--paper));

    border-radius: 0.2em;
    background: var(--highlight);
    box-shadow: 0 0 0 0.4em var(--highlight);
}

/* The documents page: <article class="documents"> holding the title in
   <h1>, the Markdown introduction in <div class="text"> and one item per
   document in <ul class="list">: the linked title in <h2 class="title">,
   the Markdown description in <div class="description"> and the link to
   the original in <p class="original">. Each item is the head of the
   document page in miniature, centred. */

article.documents {
    max-inline-size: var(--measure);
    margin-inline: auto;
    padding-block: clamp(2rem, 8vh, 5rem) clamp(3rem, 10vh, 6rem);
    padding-inline: var(--gutter);
}

/* Set like a LaTeX title, as on the person page. */
article.documents > h1 {
    margin-block: 0;
    font-size: 2em;
    font-weight: normal;
    text-align: center;
}

article.documents > .text {
    margin-block-start: 2rem;
}

article.documents > .text > :first-child {
    margin-block-start: 0;
}

/* The list: a plain stack of centred items, no markers, two lines of
   space between items so each reads as its own block. Short lines, not
   body copy, so no hyphenation. */
article.documents > .list {
    margin-block: 2rem 0;
    padding: 0;
    list-style: none;
    text-align: center;
    hyphens: manual;
}

article.documents > .list > li + li {
    margin-block-start: 2rem;
}

/* The title: the second heading size at regular weight, centred, as the
   document page sets its own title at the first. Overrides the Markdown
   heading rules, which set headings bold and ragged right. */
article.documents > .list .title {
    margin-block: 0;
    font-size: 1.35em;
    font-weight: normal;
    text-align: center;
}

/* The subtitle under the title, as on the document page, a step smaller
   to suit the smaller title. */
article.documents > .list .description {
    margin-block-start: 0.25rem;
    font-style: italic;
    text-wrap: balance;
    color: color-mix(in oklab, var(--ink) 75%, var(--paper));
}

/* The description is Markdown, so it arrives wrapped in <p>; here those
   paragraphs carry no outer margin. */
article.documents > .list .description > :first-child {
    margin-block-start: 0;
}

article.documents > .list .description > :last-child {
    margin-block-end: 0;
}

/* The original: the same aside as on the document page, set close under
   the description so the link reads as part of the block. */
article.documents > .list .original {
    margin-block-start: 0;
    font-size: 0.9em;
    color: color-mix(in oklab, var(--ink) 75%, var(--paper));
}
/* A WhatsApp chat page: <article class="chat"> holding, when any message
   is a translation, the banner in <p class="banner">, then the Markdown
   title in <div class="title"> and the thread in
   <ol class="thread">, one <li> per item: <li class="note"> for a Markdown
   note between messages (with class "bracketed" too when it reads
   `[…]`), <li class="day"> for the date wherever the day changes,
   <li class="message received"> or
   <li class="message sent"> for a message, the side given by the chat's
   point of view. A message opens with <header class="meta">, carrying the
   message's number as its id: the sender as the site's <a class="person">
   link, or, where the chat does not identify one, as
   <span class="unknown"> reading "Unknown sender", then, after a bare
   joint, " on " in English, the date in <span class="date">, closed by "(UTC)" in
   <span class="zone">, all in
   <span class="from">, then, pushed to the right in
   <span class="aside">, the link to the original when the page is a
   translation.
   A text message goes on with the Markdown text in <div class="text">
   and, when any, the attachments in <ul class="attachments">, each an
   <li> of class "document" or "file" holding a link to the document page
   or the file copy, or, with class "missing" too, the bare name of one
   not kept, followed by WhatsApp's mark, "(file attached)", in
   <span class="attached">; and last, when the message was edited, the
   mark in <footer class="edited">, pinned to the bubble's bottom corner
   beside the last line.
   A voice note, whose <li> has class "voice" too, goes on with the
   <audio> player instead, holding the link to the file as its fallback,
   then the transcript's heading in <div class="label">, "Transcript" or,
   when the page is a translation, "Translation of the transcript", and
   the transcript itself as Markdown in <div class="text">.
   Requires markdown.css and banner.css. */

article.chat {
    /* WhatsApp's bubble colours, each taken a step away from the paper so
       the bubble reads as a shape on the page, not only by its shadow: a
       shade of the paper for the received, a deeper green for the sent. */
    --bubble-received: light-dark(#f1eee8, #30302e);
    --bubble-sent: light-dark(#c9e8c0, #0b5546);
    --bubble-shadow: 0 1px 0.5px light-dark(rgb(0 0 0 / 0.13), rgb(0 0 0 / 0.5));
    /* Where a link lands a bubble: its top a fifth of the way down the
       screen, so the message reads with some of the thread above it, and
       never less than clear of the pinned header, on a short window. */
    --anchor-clearance: max(6rem, 20svh);
    /* The size of the small type in a bubble: the metadata row, the
       attachments, the transcript's heading and the edited mark. */
    --small: 0.8em;

    max-inline-size: var(--measure);
    margin-inline: auto;
    padding-block: clamp(2rem, 8vh, 5rem) clamp(3rem, 10vh, 6rem);
    padding-inline: var(--gutter);
}

/* Under a banner a landed bubble must clear the banner too, as anchors
   on the other pages do through banner.css. */
article.chat:has(> .banner) {
    --anchor-clearance: max(9rem, 20svh);
}

/* Georgian runs wider than Latin and Cyrillic, its letters being broad
   and most of them ascending, so at the same size a Georgian metadata
   row is the longest of the four and, with a long name, overruns the
   column that holds the other three. The small type takes a step down
   there: at that size Georgian sits at the Latin row's optical weight,
   and the row gets back the em or two it lacked. */
article.chat:lang(ka) {
    --small: 0.75em;
}

/* Set like a LaTeX title, as on the person page. The title is Markdown,
   so it is a <div> rather than an <h1> and takes the heading's setting
   here: the size, the tighter leading, balanced lines, no hyphenation.
   Its paragraph carries no outer margin. */
article.chat > .title {
    margin-block: 0;
    font-size: 2em;
    font-weight: normal;
    line-height: 1.2;
    text-align: center;
    text-wrap: balance;
    hyphens: manual;
}

article.chat > .title > :first-child {
    margin-block-start: 0;
}

/* The thread: a column of bubbles a little apart, with the list's markers
   and indent removed. Messages are short and set ragged right in
   WhatsApp, so the page's justification and hyphenation are switched
   off. Browsers scroll a targeted bubble under the pinned header, hence
   the scroll margin. The thread is a size container so that what a
   bubble holds can be measured against the column, in cqi, below. */
article.chat > .thread {
    display: flex;
    flex-direction: column;
    gap: 0.4em;
    margin-block: 2rem 0;
    padding: 0;
    list-style: none;
    text-align: start;
    hyphens: manual;
    container-type: inline-size;
}

article.chat > .thread > li + li {
    margin-block-start: 0;
}

/* A bubble: as wide as its widest line, rounded, edged with a hairline
   of its own colour darkened by a quarter of the ink so the outline
   holds on the paper, with WhatsApp's faint shadow beneath it. Flush
   with the column's edge on its side, as the notes are, so the thread
   has one left margin. On a phone it is at most five sixths of the
   column, so the side it hugs is always visible; from the desktop
   breakpoint that cap moves onto the bubble's contents (below), and the
   bubble itself may grow to the column for its metadata row. */
article.chat > .thread > .message {
    position: relative;
    max-inline-size: 85%;
    margin-inline: 0;
    padding-block: 0.4em 0.5em;
    padding-inline: 0.7em;
    border: 1px solid color-mix(in oklab, var(--bubble) 75%, var(--ink));
    border-radius: 0.6em;
    background: var(--bubble);
    box-shadow: var(--bubble-shadow);
    scroll-margin-block-start: var(--anchor-clearance);
}

/* What a bubble holds under its metadata row, the text and the
   attachments, or a voice note's player, heading and transcript, may
   widen it to five sixths of the column and no further, so a long
   message leaves the side it hugs visible. The row is the exception: a
   long name, date and link may take it past that, and the
   bubble widens for it as far as the column allows, since a row on one
   line reads better than a broken one over a narrow bubble. The minimum
   then spans the contents across the bubble the row has widened; it is
   a percentage, which counts for nothing in the bubble's own measure.
   The edited mark is out of the flow and pinned to a corner, so it is
   left alone. */
article.chat > .thread > .message > :not(.meta, .edited) {
    max-inline-size: 85cqi;
    min-inline-size: 100%;
}

/* Received on the left, sent on the right. The top corner on the hugged
   side is squared off in place of WhatsApp's tail, and only on the first
   bubble of a run from the same side, as WhatsApp draws it. */
article.chat > .thread > .received {
    --bubble: var(--bubble-received);
    align-self: flex-start;
    border-start-start-radius: 0;
}

article.chat > .thread > .sent {
    --bubble: var(--bubble-sent);
    align-self: flex-end;
    border-start-end-radius: 0;
}

article.chat > .thread > .received + .received {
    border-start-start-radius: 0.6em;
}

article.chat > .thread > .sent + .sent {
    border-start-end-radius: 0.6em;
}

/* The bubble a link landed on, whether by its id (the bubble itself is
   the target) or by its number (its metadata row is): ringed in the
   link colour. */
article.chat > .thread > .message:is(:target, :has(:target)) {
    box-shadow: var(--bubble-shadow), 0 0 0 2px var(--link);
}

/* The metadata row: a small line in the lighter ink of the site's
   asides, the sender's name bold as in a WhatsApp group, standing half
   a line clear of the text beneath it. The sender and date
   stand at the left; the link to the original is pushed to the far
   right, the bubble growing to hold the row on one line wherever the
   column allows. A phone's column allows no such thing, so there the
   link drops to a line of its own, still at the right. The row is the
   numeric anchor, so it needs the header clearance too. */
article.chat > .thread .meta {
    display: flex;
    flex-wrap: wrap;
    column-gap: 1em;
    margin-block-end: 0.9em;
    font-size: var(--small);
    color: color-mix(in oklab, var(--ink) 75%, var(--paper));
    scroll-margin-block-start: var(--anchor-clearance);
}

/* The words standing for a sender the chat does not identify are no
   name, but they hold the name's place in the row, between the bubble's
   side and the date, and are set as one: unmarked otherwise, since
   what they say is already plain, and upright, italics being no mark of
   a stand-in on the Russian page, where cursive lowercase is not used. */
article.chat > .thread .meta :is(.person, .unknown) {
    font-weight: bold;
}

/* The date keeps its parts together. */
article.chat > .thread .meta .date {
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

/* The time zone after the date, "(UTC)", in small capitals, as on the
   email page, so it stays below the row's already small type. */
article.chat > .thread .meta .zone {
    font-variant-caps: all-small-caps;
}

article.chat > .thread .meta .aside {
    margin-inline-start: auto;
    white-space: nowrap;
}

/* From the desktop breakpoint the bubble may grow to the column for its
   row, the cap staying on its contents alone. A window still too narrow
   for the row, or a name too long for any, breaks it inside the sender
   rather than before the link: the row is a grid, the sender's column
   taking whatever the link's leaves, so the date, or the name's last
   words, wrap under the name while the link keeps the first line's
   right end, on the name's baseline. The link's column is implicit, so
   a row without a link has neither the column nor the gap before it. */
@media (min-width: 48em) {
    article.chat > .thread > .message {
        max-inline-size: none;
    }

    article.chat > .thread .meta {
        display: grid;
        grid-template-columns: 1fr;
        grid-auto-flow: column;
        grid-auto-columns: auto;
        align-items: baseline;
    }
}

/* The text is Markdown, so it arrives wrapped in <p>; inside a bubble
   those paragraphs carry no outer margin and sit closer together than
   body paragraphs. */
article.chat > .thread .text > :first-child {
    margin-block-start: 0;
}

article.chat > .thread .text > :last-child {
    margin-block-end: 0;
}

article.chat > .thread .text p + p {
    margin-block-start: 0.6em;
}

/* Attachments close the bubble as an exported chat lists them, one file
   per line, standing a paragraph's space below the text. The name is in
   the code face as the person page sets addresses, since a file name is
   a literal string; the mark after it, "(file attached)", is WhatsApp's
   own wording and so keeps the page's face, in the aside ink. A name
   that links to nothing is dimmed: the attachment was not kept. */
article.chat > .thread .attachments {
    margin-block: 0.6em 0;
    padding: 0;
    list-style: none;
    font-family: var(--font-code);
    font-size: var(--small);
}

article.chat > .thread .attachments > li + li {
    margin-block-start: 0.15em;
}

article.chat > .thread .attachments .missing {
    color: color-mix(in oklab, var(--ink) 75%, var(--paper));
}

article.chat > .thread .attachments .attached {
    font-family: var(--font-text);
    color: color-mix(in oklab, var(--ink) 75%, var(--paper));
}

/* A voice note's bubble, <li class="message voice">, is set at one width
   whatever its transcript's length, as WhatsApp sets it at its player's
   width, and narrower only where the column leaves a bubble less than
   that; its metadata row alone may widen it, as any bubble's may. So the
   width is a minimum, and the transcript is held out of the bubble's
   measure, contributing nothing to it, and spans whatever the bubble
   came to. The browser's own player spans the bubble on a line of its
   own, and the transcript wraps beneath it. The link with the file's
   name is the player's fallback and is not drawn where a player is. */
article.chat > .thread > .voice {
    min-inline-size: min(24em, 85cqi);
}

article.chat > .thread > .voice > audio {
    display: block;
    inline-size: 100%;
}

article.chat > .thread > .voice > .text {
    contain: inline-size;
}

/* The transcript's heading, "Transcript" or, on a page in another
   language, "Translation of the transcript": WhatsApp's small grey word
   over a transcription, in the metadata row's size and ink, standing a
   little clear of the player and close over the text it heads. */
article.chat > .thread > .voice > .label {
    margin-block: 0.9em 0.3em;
    font-size: var(--small);
    color: color-mix(in oklab, var(--ink) 75%, var(--paper));
}

/* The edited mark: WhatsApp's small grey word in the bubble's bottom
   corner, in the metadata row's size and ink, on the last line of the
   bubble when that line has room for it and on a line of its own when
   not. This is done as WhatsApp does it: the mark is lifted out of the
   flow and pinned to the corner, inside the bubble's padding, and an
   invisible copy of it is appended to the last line, so the line either
   holds the copy and the mark sits where the copy is, or wraps and the
   mark takes the empty line. The copy's text is the mark's, per
   language, since a pseudo-element cannot read it off the bubble. */
article.chat > .thread .edited {
    position: absolute;
    inset-block-end: 0.5em;
    inset-inline-end: 0.7em;
    font-size: var(--small);
    color: color-mix(in oklab, var(--ink) 75%, var(--paper));
}

/* The last line is the text's last block when nothing follows it, or
   the last attachment. The copy stands a word of space clear of the
   line's end, the "comfortable room" the mark needs. Only a text message
   can be edited, so a voice note's transcript never carries the copy. */
article.chat > .thread .message:has(> .edited) > .text:not(:has(~ .attachments)) > :last-child::after,
article.chat > .thread .message:has(> .edited) > .attachments > li:last-child::after {
    content: "Edited";
    display: inline-block;
    margin-inline-start: 0.6em;
    font-family: var(--font-text);
    font-size: var(--small);
    visibility: hidden;
}

/* The attachments are already at the mark's size. */
article.chat > .thread .message:has(> .edited) > .attachments > li:last-child::after {
    font-size: 1em;
}

article.chat > .thread .message:has(> .edited) > .text:not(:has(~ .attachments)) > :last-child:lang(pt)::after,
article.chat > .thread .message:has(> .edited) > .attachments > li:last-child:lang(pt)::after {
    content: "Editada";
}

article.chat > .thread .message:has(> .edited) > .text:not(:has(~ .attachments)) > :last-child:lang(ru)::after,
article.chat > .thread .message:has(> .edited) > .attachments > li:last-child:lang(ru)::after {
    content: "Изменено";
}

article.chat > .thread .message:has(> .edited) > .text:not(:has(~ .attachments)) > :last-child:lang(ka)::after,
article.chat > .thread .message:has(> .edited) > .attachments > li:last-child:lang(ka)::after {
    content: "რედაქტირებულია";
}

/* The date where the day changes, <li class="day">: WhatsApp's day chip,
   a small rounded box centred between the bubbles, in the received
   bubble's colour, hairline and shadow, holding the date in the aside
   ink, a little smaller. The corner is the bubbles' own, 0.6em of the
   thread's type, restated in the chip's smaller type. */
article.chat > .thread > .day {
    --bubble: var(--bubble-received);
    align-self: center;
    margin-block: 0.8em;
    padding-block: 0.3em;
    padding-inline: 0.8em;
    border: 1px solid color-mix(in oklab, var(--bubble) 75%, var(--ink));
    border-radius: 0.7em;
    background: var(--bubble);
    box-shadow: var(--bubble-shadow);
    font-size: 0.85em;
    text-align: center;
    color: color-mix(in oklab, var(--ink) 75%, var(--paper));
}

/* A note between messages: the author's prose in the page's own text,
   spanning the column, standing a good line clear of the bubbles on
   either side so it reads as a break in the thread, not as part of the
   exchange. Being prose, it takes back the page's paragraphs, justified
   and hyphenated, which the thread switches off for the bubbles. */
article.chat > .thread > .note {
    align-self: stretch;
    margin-block: 1.5em;
    text-align: justify;
    -webkit-hyphens: auto;
    hyphens: auto;
}

/* A bracketed note, `[Messages omitted]`, is an editorial notice and is
   centred as WhatsApp centres its own, so it keeps its words whole. */
article.chat > .thread > .bracketed {
    align-self: center;
    max-inline-size: 85%;
    text-align: center;
    -webkit-hyphens: manual;
    hyphens: manual;
}

article.chat > .thread > .note > :first-child {
    margin-block-start: 0;
}

article.chat > .thread > .note > :last-child {
    margin-block-end: 0;
}

/* Italic Cyrillic swaps the lowercase for cursive shapes that are not
   used in correspondence, so on the Russian page an italic note stays
   upright. */
article.chat > .thread > .note em:lang(ru) {
    font-style: normal;
}

/* The chats page: <article class="chats"> holding the title in <h1>, the
   Markdown introduction in <div class="text"> and one row per chat in
   <table class="list">: the Markdown description in <td class="description">
   and, in <td class="chat">, the button to the chat page. */

article.chats {
    max-inline-size: var(--measure);
    margin-inline: auto;
    padding-block: clamp(2rem, 8vh, 5rem) clamp(3rem, 10vh, 6rem);
    padding-inline: var(--gutter);
}

/* Set like a LaTeX title, as on the person page. */
article.chats > h1 {
    margin-block: 0;
    font-size: 2em;
    font-weight: normal;
    text-align: center;
}

article.chats > .text {
    margin-block-start: 2rem;
}

article.chats > .text > :first-child {
    margin-block-start: 0;
}

/* The list: an open table with no rules, a line of space between rows
   and a word of space between columns, as the emails list. The
   description takes whatever width the button leaves, so it is the only
   column that wraps. */
article.chats > .list {
    inline-size: 100%;
    margin-block-start: 2rem;
    border-collapse: collapse;
    text-align: start;
}

article.chats > .list td {
    padding: 0;
    vertical-align: middle;
}

article.chats > .list tr + tr > td {
    padding-block-start: 1em;
}

article.chats > .list td + td {
    padding-inline-start: 1.5em;
}

article.chats > .list .description {
    inline-size: 100%;
}

/* The description is Markdown, so it arrives wrapped in <p>; inside a
   table cell those paragraphs carry no outer margin. */
article.chats > .list .description > :first-child {
    margin-block-start: 0;
}

article.chats > .list .description > :last-child {
    margin-block-end: 0;
}

/* The button: the link set in a rounded hairline frame in the link's own
   colour, on one line, closing the row at the right and centred on a
   description that runs to several lines. Underlined only on hover, as
   the language switch is, since the frame already marks it a link. */
article.chats > .list .chat {
    text-align: end;
    white-space: nowrap;
}

article.chats > .list .chat > a {
    display: inline-block;
    padding-block: 0.15em;
    padding-inline: 0.7em;
    border: 1px solid color-mix(in oklab, currentColor 50%, transparent);
    border-radius: 0.5em;
    text-decoration-line: none;
}

article.chats > .list .chat > a:hover {
    text-decoration-line: underline;
}
/* The news page: <article class="news"> holding the title in <h1>, the
   Markdown introduction in <div class="text"> and one entry per item in
   <ol class="items">. Each <li class="item"> carries the item's id as its
   anchor, which the feed's item link lands on, and holds the Markdown
   title in <div class="title">, the date in <div class="date">, closed by
   "(UTC)" in <span class="zone">, and the Markdown body in
   <section class="body">. Laid out like the documents
   page; an entry is the plain page in miniature, opening under a rule
   with its title and date at the left over a body of prose. Requires
   markdown.css. */

article.news {
    /* Clear of the pinned header when a feed's link lands on an entry, as
       on the chat page. */
    --anchor-clearance: 6rem;

    max-inline-size: var(--measure);
    margin-inline: auto;
    padding-block: clamp(2rem, 8vh, 5rem) clamp(3rem, 10vh, 6rem);
    padding-inline: var(--gutter);
}

/* Set like a LaTeX title, as on the person page. */
article.news > h1 {
    margin-block: 0;
    font-size: 2em;
    font-weight: normal;
    text-align: center;
}

article.news > .text {
    margin-block-start: 2rem;
}

article.news > .text > :first-child {
    margin-block-start: 0;
}

/* The entries: a plain stack, no markers, the ordinals of the <ol> being
   for the order alone. */
article.news > .items {
    margin-block: 3rem 0;
    padding: 0;
    list-style: none;
}

article.news > .items > .item {
    scroll-margin-block-start: var(--anchor-clearance);
}

/* Each entry, the first as well, opens under a rule across the column,
   so every one reads as its own block and the first is parted from the
   introduction: the blocks are prose, and prose that runs the width of
   the column needs more than space to be told apart. The rule is
   heavier and darker than the site's hairlines, since it is what marks
   where one entry ends and the next begins, and the space above it is
   twice the space below, so the rule belongs to the entry it opens. */
article.news > .items > .item {
    padding-block-start: 1.5rem;
    border-block-start: 2px solid color-mix(in oklab, var(--ink) 45%, var(--paper));
}

article.news > .items > .item + .item {
    margin-block-start: 3rem;
}

/* The entry a feed's link landed on, ringed in the link colour as a
   bubble is on the chat page. The ring stands off the text far enough to
   clear the hairline above. */
article.news > .items > .item:target {
    outline: 2px solid var(--link);
    outline-offset: 0.75rem;
    border-radius: 2px;
}

/* The date stands under the title, close to it and at the left with it,
   a small line in the lighter ink of the site's asides, as the emails
   list sets its dates. It is plain text: the entry's anchor is the <li>,
   which the feed's link lands on, and the page cites no date of its
   own. */
article.news > .items > .item > .date {
    margin-block-start: 0.35rem;
    font-size: 0.9em;
    text-align: start;
    hyphens: manual;
    color: color-mix(in oklab, var(--ink) 75%, var(--paper));
}

/* The time zone after the date, "(UTC)", in small capitals, as on the
   email page. */
article.news > .items > .item > .date > .zone {
    font-variant-caps: all-small-caps;
}

/* The title heads the entry at the left, at regular weight, as the site
   sets its titles, and a step larger than the second heading size, so
   it is not taken for a heading of the body before it, which Markdown
   sets bold and at most at that size. The title is Markdown, so it is a
   <div> and takes the heading's setting here, as on the plain page: the
   size, the tighter leading, balanced lines, no hyphenation. Its
   paragraph carries no outer margin. */
article.news > .items > .item > .title {
    margin-block: 0;
    font-size: 1.6em;
    font-weight: normal;
    line-height: 1.2;
    text-align: start;
    text-wrap: balance;
    hyphens: manual;
}

article.news > .items > .item > .title > :first-child {
    margin-block-start: 0;
}

article.news > .items > .item > .title > :last-child {
    margin-block-end: 0;
}

/* The body is the body of the page, as on the plain page, set closer to
   its title than a page's is to its own, the entry being one block of the
   stack rather than a page; the date sits in that gap. */
article.news > .items > .item > .body {
    margin-block-start: 1rem;
}

article.news > .items > .item > .body > :first-child {
    margin-block-start: 0;
}

article.news > .items > .item > .body > :last-child {
    margin-block-end: 0;
}
/* A plain page: <article class="page"> holding, when the page is an
   unverified translation, the banner in <p class="banner">, then the
   Markdown title in <div class="title">, the date in <div class="date">
   and the Markdown body in <section class="body">. Laid out like the
   entity page. Requires markdown.css and banner.css. */

article.page {
    max-inline-size: var(--measure);
    margin-inline: auto;
    padding-block: clamp(2rem, 8vh, 5rem) clamp(3rem, 10vh, 6rem);
    padding-inline: var(--gutter);
}

/* Set like a LaTeX title, as on the person page. The title is Markdown,
   so it is a <div> rather than an <h1> and takes the heading's setting
   here, as on the chat page: the size, the tighter leading, balanced
   lines, no hyphenation. Its paragraph carries no outer margin. */
article.page > .title {
    margin-block: 0;
    font-size: 2em;
    font-weight: normal;
    line-height: 1.2;
    text-align: center;
    text-wrap: balance;
    hyphens: manual;
}

article.page > .title > :first-child {
    margin-block-start: 0;
}

article.page > .title > :last-child {
    margin-block-end: 0;
}

/* The date under the title, as under a LaTeX title: centred, a little
   below it, in the lighter ink of the date on the news page. */
article.page > .date {
    margin-block-start: 1rem;
    text-align: center;
    hyphens: manual;
    color: color-mix(in oklab, var(--ink) 75%, var(--paper));
}

/* The body is the body of the page, as the record is on the entity page. */
article.page > .body {
    margin-block-start: 2rem;
}

article.page > .body > :first-child {
    margin-block-start: 0;
}

/* Where a link lands on an anchor in the page: its top a little above the
   middle of the screen, so the passage reads with what leads up to it, and
   never less than clear of the pinned header, on a short window, as on the
   email page. */
article.page [id] {
    scroll-margin-block-start: max(6rem, 40svh);
}

/* The block of the body a link landed on, whether the anchor is the block
   itself or a few words inside it: tinted with the link colour, so the eye
   finds it at once, as on the email page. The tint spills a little past
   the text through the shadow, which takes no room, so nothing around it
   moves. */
article.page > .body > :is(:target, :has(:target)) {
    --highlight: color-mix(in oklab, var(--link) 7%, var(--paper));

    border-radius: 0.2em;
    background: var(--highlight);
    box-shadow: 0 0 0 0.4em var(--highlight);
}
/* A statute page: <article class="statute"> holding the banner to the
   original text in <p class="banner">, a plain link, and the Markdown
   text in <section class="text">, which carries its own title and
   headings. Laid out like the document page, with the banner pinned under
   the header by banner.css. Requires markdown.css and banner.css. */

article.statute {
    max-inline-size: var(--measure);
    margin-inline: auto;
    padding-block: clamp(2rem, 8vh, 5rem) clamp(3rem, 10vh, 6rem);
    padding-inline: var(--gutter);
}

/* The text's blocks take their spacing from markdown.css, as the
   document's text does. Whatever it opens with sits flush against the gap
   above, and its last block adds nothing to the article's padding. */
article.statute > .text > :first-child {
    margin-block-start: 0;
}

article.statute > .text > :last-child {
    margin-block-end: 0;
}

/* The block of the text a link landed on, whether the anchor is the block
   itself or a few words inside it: tinted with the link colour, so the eye
   finds it at once, as on the email and document pages. The tint spills a
   little past the text through the shadow, which takes no room, so nothing
   around it moves. */
article.statute > .text > :is(:target, :has(:target)) {
    --highlight: color-mix(in oklab, var(--link) 7%, var(--paper));

    border-radius: 0.2em;
    background: var(--highlight);
    box-shadow: 0 0 0 0.4em var(--highlight);
}
/* The root index.html, written in one fixed language and without the page
   header: <main class="index"> holding the site's Markdown header in
   <div class="title">, no link here, then one card per language in
   <nav class="cards">, each a link to the main page in that language
   carrying the language's flag in <span class="flag"> and its name, in
   itself, in <span class="name">. Laid out like the plain page. Requires
   markdown.css. */

main.index {
    max-inline-size: var(--measure);
    margin-inline: auto;
    padding-block: clamp(2rem, 8vh, 5rem) clamp(3rem, 10vh, 6rem);
    padding-inline: var(--gutter);
}

/* Set like a LaTeX title, as on the plain page: the size, the tighter
   leading, centred and balanced lines, no hyphenation. Its paragraphs
   carry no outer margin. */
main.index > .title {
    font-size: 2em;
    line-height: 1.2;
    text-align: center;
    text-wrap: balance;
    hyphens: manual;
}

main.index > .title > :first-child {
    margin-block-start: 0;
}

main.index > .title > :last-child {
    margin-block-end: 0;
}

/* The cards: one row each, stacked in a column narrower than the text,
   centred under the title, so a card is no wider than a name needs. */
main.index > .cards {
    max-inline-size: 18em;
    margin-block-start: 3rem;
    margin-inline: auto;
}

main.index > .cards > ul {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

main.index > .cards li + li {
    margin-block-start: 0;
}

/* Each card is a whole link: a box ruled like the header holding the flag
   and, to its right, the name, as in the language switch, a step larger
   than the text, in the text colour and never underlined. The flags line
   up down the column, and so do the names. On hover the rule takes the
   link colour and the box a faint tint of it. The focus ring comes from
   markdown.css, rounded here with the box. */
main.index > .cards a {
    display: flex;
    align-items: center;
    gap: 0.6em;
    padding: 0.6em 1em;
    border: 1px solid var(--rule);
    border-radius: 0.5em;
    font-size: 1.2em;
    color: var(--ink);
    text-decoration-line: none;
    text-align: start;
    hyphens: manual;
}

main.index > .cards a:hover {
    border-color: var(--link);
    background: color-mix(in oklab, var(--link) 6%, var(--paper));
}

/* Flags are colour glyphs whose baselines differ between platform fonts,
   so the flag is centred on the name rather than trusting them, as the
   contact glyphs are on the person page. A unit line height keeps the
   slot no taller than the glyph itself. */
main.index > .cards .flag {
    font-size: 1.5em;
    line-height: 1;
}/* The banner: <p class="banner"> as the first child of an article, held
   just under the header while the page scrolls. The statute page's
   holds the link to the original text; the person, entity, estate,
   email, document, plain and chat pages' warn, when the page is a
   translation, that it may contain errors. Loaded after the pages' own
   stylesheets, since it takes over their opening gap. Requires
   header.css. */

/* The banner sits right under the header's rule, so the page opens with
   it; the gap other pages open with comes after the banner instead. */
article:has(> .banner) {
    padding-block-start: 0;
}

/* A strip as wide as the header, reaching past the article's gutters,
   holding one centred line in the smaller size of the site's asides, in
   the text's own ink, closed by a rule like the header's. The paper
   background keeps passing text from showing through. */
article > .banner {
    margin-block: 0 clamp(2rem, 8vh, 5rem);
    margin-inline: calc(-1 * var(--gutter));
    padding-block: 0.5rem;
    padding-inline: var(--gutter);
    border-block-end: 1px solid var(--rule);
    background: var(--paper);
    font-size: 0.9em;
    text-align: center;
    hyphens: manual;
}

/* The header is pinned, and its height follows the masthead, so the
   banner is fixed to the window and hung from the header's lower edge
   through anchor positioning. Being fixed it takes no room, so the
   article opens with the banner's height, one line of the aside's size
   and its padding and rule, before the usual gap; a banner wrapping to a
   second line on a phone eats into that gap rather than the text. Without
   anchor positioning the banner cannot find the header's edge, so it
   stays at the top of the article and scrolls away with it rather than
   hide beneath the header.

   The header opens the body and sticks at the top, so it never leaves the
   window's top edge, and its lower edge lies as far down as the header is
   tall. The banner is hung by the header's size rather than its position:
   a position must follow the sticky header through the scroll, which
   Firefox on Android does out of step with the scroll, so the banner
   wandered over the page as it scrolled. A size does not move. */
@supports (inset-block-start: anchor-size(--site-header block)) {
    body:has(> article > .banner) > header {
        anchor-name: --site-header;
    }

    article:has(> .banner) {
        padding-block-start: calc(1rem + 0.9em * 1.5 + 1px + clamp(2rem, 8vh, 5rem));
    }

    article > .banner {
        position: fixed;
        z-index: 1;
        inset-block-start: anchor-size(--site-header block);
        inset-inline: 0;
        max-inline-size: var(--measure);
        margin: 0 auto;
    }
}

/* Where a link lands on an anchor under a banner: as on each page, but
   never less than clear of the pinned header and banner together, on a
   short window. */
article:has(> .banner) [id] {
    scroll-margin-block-start: max(9rem, 40svh);
}
