/* tsbelgie.be — near-mono with one madder accent, one radius (7px) shared by the mark,
   the cards, the buttons and the viewer, system sans in the text and a named serif in
   the mark, single column.
   Class vocabulary is state-first (is-, has-); structure rides on element selectors.

   The accent is used in a fixed set of places and nowhere else: the mark, the rule under
   every h2, the current nav item, the primary fact, and the forward action. Spread wider
   it stops being a signal; used once it reads as an accident. */

:root {
    /* Not black on white. A neutral grey sheet is how a document looks, and a document is
       the wrong thing for a page whose subject is people and photographs: on pure white
       the pictures float, and the rules between them read as a spreadsheet.
       So the ground is warm and slightly off-paper, and the ink is brown-black rather
       than neutral. Both stay quiet enough to keep photographs the loudest thing. */
    --ink: #1c1512;
    --paper: #faf6f2;
    --card: #fff;
    --line: #e2d8d0;
    --dim: #6e6058;
    --wash: #f2e9e2;
    /* One accent, and it earns its place by carrying the mark. Deep madder: dark enough
       to sit beside black without competing, and not the pink/violet every trans-niche
       site reaches for — that palette would become a giveaway shared by two of them the
       moment a second one is built. Contrast on paper is 7.4:1, so it may carry text. */
    --accent: #8c2230;
}

* { box-sizing: border-box; }

body {
    /* A column at least as tall as the window, with the sheet below taking the slack.
       Without it the footer sits wherever the content happened to end, and a page shorter
       than the window — the age check, the rules, a 404, a place with nothing in it yet —
       leaves a band of bare ground under it. */
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    margin: 0;
    background: var(--paper);
    color: var(--ink);
    font: 16px/1.55 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif;
    font-variant-numeric: tabular-nums;
}

/* Wider than a reading measure: this is a catalogue, and the width is spent on more
   cards per row rather than on longer lines. Prose is held back to 68ch separately. */
.shell {
    width: 100%;
    max-width: 1180px;
    margin: 0 auto;
    padding: 0 20px;
}

/* --- header ------------------------------------------------------------ */

header {
    border-bottom: 2px solid var(--ink);
}

header .shell,
footer .shell {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding-top: 14px;
    padding-bottom: 14px;
}

/* The lockup: ONE framed field holding both parts, divided by a rule — not a filled box
   with a word standing outside it. The frame belongs to the mark instead of surrounding
   it, which is the difference between a logo and letters in a square; the square is what
   every generator produces by default and what read as "free directory".

   Sized in em so the whole mark scales from one font-size, and set in a stack that is
   named rather than inherited from the body: a mark whose letterforms change per reader
   is a caption, not a mark. */
.lockup {
    display: inline-flex;
    align-items: stretch;
    text-decoration: none;
    color: inherit;
    border: 2px solid var(--ink);
    /* 7px, the site's one radius — the same on the cards, the buttons and the viewer.
       One value everywhere is what makes the corner read as a decision; a mark rounded
       alone reads as an exception someone forgot to apply elsewhere. Hence `radius: soft`
       rather than `mixed`. */
    border-radius: 7px;
    overflow: hidden;
    font-family: Georgia, "Iowan Old Style", "Times New Roman", serif;
    font-size: 22px;
    line-height: 1;
}

/* TS: the quiet half. Small caps weight, accent ground, divided from the word by the
   frame's own rule rather than by a gap. */
.monogram {
    display: flex;
    align-items: center;
    background: var(--accent);
    color: var(--paper);
    font-weight: 700;
    font-size: .72em;
    letter-spacing: .12em;
    padding: .42em .5em .42em .56em;
}

/* België: the half that is read. Carries the diaeresis — `Belgie` is a misspelling to
   every Belgian, and the domain cannot hold one but the mark can. */
.wordmark {
    display: flex;
    align-items: center;
    padding: .3em .55em .3em .5em;
    font-weight: 400;
    letter-spacing: .005em;
}

header nav,
footer nav {
    display: flex;
    flex-wrap: wrap;
    gap: 18px;
    font-size: 14px;
}

header nav a,
footer nav a {
    color: var(--dim);
    text-decoration: none;
}

header nav a:hover,
footer nav a:hover { color: var(--ink); }

/* Where you are, in the brand colour rather than in bold — the same red that marks the
   section you are reading and the step forward. */
header nav a.is-current {
    color: var(--accent);
    font-weight: 600;
    box-shadow: inset 0 -2px 0 var(--accent);
}

/* --- text -------------------------------------------------------------- */

main { padding: 26px 0 40px; }

h1 {
    font-size: 25px;
    line-height: 1.25;
    font-weight: 700;
    margin: 0 0 12px;
}

/* Each section opens with a short accent rule. It is the most repeated brand mark on the
   page — a reader meets it on every screen, unlike the wordmark in the header, which they
   pass once. */
h2 {
    font-size: 17px;
    font-weight: 600;
    margin: 30px 0 10px;
    padding-top: 9px;
    border-top: 3px solid var(--accent);
    display: table;
    padding-right: 28px;
}

p { margin: 0 0 14px; max-width: 68ch; }

a { color: var(--ink); }

/* Where the keyboard is. The site had no focus style at all, and the card overlay makes
   that worse rather than neutral: the browser's default ring is drawn around the LINK,
   which on a card is the name in the corner, while the thing that answers Enter is the
   whole tile. The ring is drawn in the brand colour and offset, so it reads on the warm
   ground and on a photograph alike.
   `:focus-visible` and not `:focus` — a mouse click on a card must not leave a ring
   behind it. */
a:focus-visible,
.action:focus-visible {
    outline: 3px solid var(--accent);
    outline-offset: 2px;
    border-radius: 3px;
}

.is-lead { font-size: 17px; }

.is-breadcrumb {
    font-size: 13px;
    color: var(--dim);
    margin: 0 0 14px;
}

.is-breadcrumb a { color: var(--dim); }

.is-fineprint {
    font-size: 12px;
    color: var(--dim);
    margin: 0;
}

.is-empty {
    border: 1px solid var(--line);
    border-radius: 7px;
    padding: 16px;
    color: var(--dim);
}

/* --- facts ------------------------------------------------------------- */

.has-facts {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin: 0 0 6px;
    padding: 0;
    list-style: none;
    font-size: 13px;
}

.has-facts li {
    border: 1px solid var(--line);
    border-radius: 5px;
    padding: 3px 9px;
}

/* The one fact worth reading first — how many ads are here — carries the accent; the
   rest of the row stays grey-bordered so that it can. */
.has-facts li.is-primary {
    border-color: var(--accent);
    color: var(--accent);
    font-weight: 600;
}

/* --- table: the listing unit of this site ------------------------------ */

.rows {
    width: 100%;
    border-collapse: collapse;
    font-size: 15px;
}

.rows caption {
    text-align: left;
    font-size: 13px;
    color: var(--dim);
    padding: 0 0 8px;
}

.rows th {
    text-align: left;
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .05em;
    color: var(--dim);
    border-bottom: 2px solid var(--ink);
    padding: 0 10px 7px 0;
}

.rows td {
    border-bottom: 1px solid var(--line);
    padding: 9px 10px 9px 0;
    vertical-align: middle;
}

.rows td:last-child,
.rows th:last-child { padding-right: 0; text-align: right; }

.rows tbody tr:hover { background: var(--wash); }

.rows a { text-decoration: none; font-weight: 500; }
.rows a:hover { text-decoration: underline; }

.rows .is-count { color: var(--dim); font-size: 13px; }

/* The rate, in the brand colour — it is the number the reader is comparing, and the one
   thing on a card worth finding without reading. */
.is-price {
    color: var(--accent);
    font-weight: 700;
    font-size: 15px;
    white-space: nowrap;
}

/* Age sits under the name rather than beside it: on a card the two are one block about
   one person, and the second line is where a reader expects the qualifier. */
.rows.is-people td .is-count { display: block; margin-top: 2px; }

/* The count cell links to the same page as the name beside it, so the whole row is
   aimed at rather than just its first word. It fills the cell to be worth aiming at. */
.rows td.is-count a { display: block; color: inherit; text-decoration: none; }

/* The place cell: name and blurb are one link filling the row, so the target is the line
   rather than the first two words of it. */
.rows td.is-place a { display: block; font-weight: 400; }
.rows td.is-place strong { font-weight: 600; }
.rows td.is-place a:hover strong { text-decoration: underline; }

/* The thumbnail in a listing row. Sized to be looked AT, not to mark the row: on a
   listing the picture is the thing being offered, and 48px wide made it a bullet point.
   Square-cornered, like everything else here. */
.rows td.has-photo { width: 108px; padding-right: 14px; }

.rows td.has-photo img {
    display: block;
    width: 96px;
    height: 128px;
    object-fit: cover;
    background: var(--wash);
}

/* The whole photo cell is the link, not just the name beside it. A picture that opens
   nothing is the largest dead target on the page: it is what the reader aims at first,
   because it is what they came to look at. */
.rows td.has-photo a {
    display: block;
    width: 96px;
}

/* --- the people listing widens; the place listing does not -------------------
   A table of people read down one column wastes the screen: at 940px the rows are
   108px of photo, a name, and 700px of nothing. So from 720px up the rows become grid
   items and stand side by side.

   `display: grid` on tbody keeps the table SEMANTICS — the axis of this site is
   `table-rows`, and it stays a table for a reader who cannot see the layout — while
   dropping only the tabular BOX model, which is what forced the single file.
   The head goes: column labels describe columns, and there are none once the rows sit
   beside each other. The place tables keep theirs, which is why this is scoped to
   `.is-people` and not to `.rows`. */
@media (min-width: 700px) {
    .rows.is-people thead { display: none; }

    .rows.is-people tbody {
        display: grid;
        grid-template-columns: repeat(auto-fill, minmax(min(220px, 100%), 1fr));
        gap: 18px 20px;
    }

    /* A card on the warm ground, not a ruled line across it. The rule was what made the
       listing read as a document; the card is what makes a photograph look placed.

       The photo stays a THUMBNAIL beside the text and does not grow to fill the card.
       Tried the other way — full-width picture, words beneath — and it is wrong for this
       listing: a wall of large photographs is the shape of a gallery, and this is a
       directory that happens to have pictures. What fixes an empty-looking card is more
       to read in it, not a bigger image. */
    .rows.is-people tr {
        display: grid;
        grid-template-columns: auto 1fr;
        grid-template-rows: auto 1fr;
        align-items: start;
        column-gap: 12px;
        background: var(--card);
        border: 1px solid var(--line);
        /* Same radius as the mark, so the two read as one system rather than as two
           decisions. The photo inside is clipped to match — a square corner poking out
           of a rounded card is what makes rounding look accidental. */
        border-radius: 7px;
        padding: 10px;
    }

    .rows.is-people td.has-photo img { border-radius: 4px; }

    .rows.is-people td { border: 0; padding: 0; }

    /* The name must be able to shrink: a grid item is min-content wide by default, so a
       long name pushes its own cell past the column and the whole grid drifts wider. */
    .rows.is-people td:not(.has-photo) { min-width: 0; }

    .rows.is-people td.has-photo {
        grid-row: span 2;
        width: auto;
        padding: 0;
    }

    /* The rate sits at the foot of the text column, opposite the photo — the card reads
       name, then who, then what it costs. */
    .rows.is-people td.is-count { text-align: left; align-self: end; }

    /* Hover belonged to the row when the row was a full-width band. As a card it is the
       border that answers — the brand colour, same as everywhere the site says "here". */
    .rows.is-people tbody tr:hover {
        background: var(--card);
        border-color: var(--accent);
    }

    .rows.is-people tbody tr:hover a { text-decoration: underline; }

    /* The whole card is the target, not the photo and the name with dead padding around
       them. The name's link stretches over the entire tile with a positioned ::after.
       One link, so a screen reader still hears the card announced once.

       ⚠️ These two rules must come LAST in this block. `.rows.is-people tr` is declared
       above as well, and the later declaration wins — placed earlier, `position: relative`
       was overridden back to static and the overlay measured itself against the page
       instead of the card. It looked correct in the file and covered nothing: every click
       outside the name landed on a dead `<td>`. */
    .rows.is-people tr { position: relative; cursor: pointer; }

    /* ⚠️ The NAME cell only. Written as `td:not(.has-photo)` it also matched the price
       cell, and the moment a link goes in there — the obvious next step, "the rate opens
       the ad" — two `inset: 0` overlays lie on top of each other and the later one takes
       every click. Correct only by coincidence is not correct: `.rows td.is-count a`
       already exists for the places table two rules below. */
    .rows.is-people td.is-name a::after {
        content: "";
        position: absolute;
        inset: 0;
        border-radius: 7px;
    }

    /* The ring goes round the CARD, because the card is what Enter presses. Left on the
       link it would circle the name in the corner and tell the keyboard reader that a
       word is selected when a whole tile is. */
    .rows.is-people td.is-name a:focus-visible { outline: none; }

    .rows.is-people tr:has(td.is-name a:focus-visible) {
        outline: 3px solid var(--accent);
        outline-offset: 2px;
    }
}

/* Below the grid the table drops its header and each row becomes a line.
   ⚠️ The bound is 699.98px, not 560px, and it has to meet the grid's 700px exactly:
   at 560/720 there were 159 pixels where NEITHER applied and the browser fell back to
   the plain table box model — header row visible, one column, no overlay. That band is
   not empty space, it is a phone held sideways and a half-width desktop window. */
@media (max-width: 699.98px) {
    .rows thead { display: none; }
    .rows, .rows tbody, .rows tr, .rows td { display: block; width: 100%; }
    .rows tr {
        border-bottom: 1px solid var(--line);
        padding: 9px 0;
        display: flex;
        align-items: center;
        gap: 11px;
    }
    .rows td { border: 0; padding: 0; }
    .rows td:first-child { flex: 1; min-width: 0; }
    .rows td:last-child { text-align: right; flex: none; }
    .rows td.has-photo { width: 96px; flex: none; }
}

/* --- profile ----------------------------------------------------------- */

.gallery {
    display: flex;
    gap: 8px;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    margin: 0 0 18px;
    padding: 0 0 6px;
}

/* Every thumbnail the same size. Height `auto` let each photo keep its own proportion,
   so a strip of portrait and landscape shots came out ragged along the bottom — the
   pictures are DATA and arrive in whatever shape the donor uploaded, so the frame has to
   be fixed and the photo cropped into it. */
.gallery img {
    flex: 0 0 auto;
    scroll-snap-align: start;
    /* ⚠️ Sized to the PREVIEW file, not to taste: Matilda's thumbnails run 87px wide, and
       a 200px tile enlarged them well past the point where the strip reads as sharp. The
       full-size image is one tap away in the viewer. */
    width: min(120px, 40vw);
    aspect-ratio: 3 / 4;
    height: auto;
    object-fit: cover;
    background: var(--wash);
    border-radius: 5px;
}

/* --- viewer -------------------------------------------------------------
   Full-size photos over the page, no script: `:target` opens it, and because the
   browser's own history does the opening, Back closes it. Hidden by default, and hidden
   again the moment the target is the container itself (`#fotos`) — that is what the
   close link points at. */
.viewer {
    display: none;
    position: fixed;
    inset: 0;
    z-index: 20;
    /* Nearly opaque. At .94 the page stayed legible underneath and competed with the
       photograph — the point of the viewer is that there is one thing to look at. */
    background: rgba(20, 15, 13, .985);
    overflow-x: auto;
    overflow-y: hidden;
    scroll-snap-type: x mandatory;
}

/* :has() lets the container react to a targeted child.

   ⚠️ The comment that stood here — "nothing is lost but the enlargement" — was wrong,
   and the difference matters. The strip holds the `full` files; the thumbnails above
   hold `preview` ones. They are different files at different resolutions, so a browser
   without :has() does not fall back to a smaller picture: the viewer stays
   `display: none` and every thumbnail becomes a link that visibly does nothing.

   Hence the second selector. `figure:target ~ *` cannot reach an ancestor and there is
   no ancestor combinator without :has(), so the fallback works the other way round: the
   figures are laid out visibly by default, and :has() COLLAPSES them into the overlay.
   A browser with :has() gets the viewer; one without gets the photos in the flow of the
   page, full size, which is what they were before this change. */
.viewer:has(figure:target) { display: flex; }

@supports not selector(:has(*)) {
    /* No overlay here — just the full-size photos in the page, one after another. Plain,
       and every one of them reachable. */
    .viewer {
        display: block;
        position: static;
        background: none;
        overflow: visible;
    }

    .viewer .is-arrow,
    .viewer .is-shut { display: none; }

    .viewer img { max-width: 100%; max-height: none; }

    .viewer figcaption { color: var(--dim); }
}

.viewer figure {
    flex: 0 0 100%;
    scroll-snap-align: center;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 14px;
    margin: 0;
    padding: 20px;
}

.viewer img {
    max-width: 100%;
    max-height: 78vh;
    width: auto;
    height: auto;
    object-fit: contain;
    border-radius: 7px;
}

.viewer figcaption {
    color: var(--paper);
    font-size: 14px;
    opacity: .75;
}

/* ⚠️ Only the open photo shows its controls. `position: fixed` takes them out of the
   strip, so EVERY figure's arrows pile up at the same two screen edges — with seven
   photos that is six dead links stacked over the live one, and the last in document
   order wins the click. The reader on photo 3 presses "next" and lands wherever the
   LAST figure's arrow points, while the caption still reads `3 / 7`. Found by review,
   not by clicking: with two photos the stack has one member and behaves correctly. */
.viewer figure:not(:target) .is-arrow,
.viewer figure:not(:target) .is-shut { display: none; }

/* Arrows on the photograph, at the edges of the screen — that is where a hand goes, and
   a row of words under the picture never reads as "next". Fixed rather than absolute so
   they stay put while the strip scrolls under them. */
.viewer .is-arrow,
.viewer .is-shut {
    position: fixed;
    z-index: 2;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--paper);
    text-decoration: none;
    background: rgba(20, 15, 13, .55);
    border: 1px solid rgba(250, 246, 242, .35);
    border-radius: 7px;
}

.viewer .is-arrow {
    top: 50%;
    transform: translateY(-50%);
    width: 52px;
    height: 72px;
    font-size: 34px;
    line-height: 1;
}

.viewer .is-back { left: 16px; }
.viewer .is-on { right: 16px; }

.viewer .is-shut {
    top: 16px;
    right: 16px;
    width: 44px;
    height: 44px;
    font-size: 26px;
}

.viewer .is-arrow:hover,
.viewer .is-shut:hover {
    background: var(--accent);
    border-color: var(--accent);
}

/* On a phone the arrows would cover most of the picture. The swipe is already the
   browser's own gesture there, so only the close button stays. */
@media (max-width: 560px) {
    .viewer .is-arrow { display: none; }
}

.has-pairs {
    margin: 0 0 18px;
    border-top: 1px solid var(--line);
    font-size: 15px;
}

.has-pairs > div {
    display: flex;
    justify-content: space-between;
    gap: 16px;
    border-bottom: 1px solid var(--line);
    padding: 7px 0;
}

.has-pairs dt { color: var(--dim); margin: 0; }
.has-pairs dd { margin: 0; text-align: right; }

.has-tags {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    padding: 0;
    margin: 0 0 18px;
    list-style: none;
    font-size: 13px;
}

.has-tags li {
    border: 1px solid var(--line);
    padding: 3px 9px;
}

/* --- button ------------------------------------------------------------ */

/* The step forward is the accent filled in — the only solid patch of it besides the mark,
   which is what makes both read as the same brand rather than two red things. */
.action {
    display: inline-block;
    background: var(--accent);
    color: var(--paper);
    text-decoration: none;
    font-weight: 600;
    padding: 11px 20px;
    border: 2px solid var(--accent);
    border-radius: 7px;
}

.action:hover { background: var(--paper); color: var(--accent); }

/* The step back is outlined, not filled: it is the same colour at a lower volume, so the
   pair reads as one control with a direction. */
.action.is-quiet {
    background: var(--paper);
    color: var(--ink);
    border-color: var(--line);
}

.action.is-quiet:hover { background: var(--wash); border-color: var(--ink); }

/* --- pager ------------------------------------------------------------- */

.pager {
    display: flex;
    gap: 10px;
    margin: 22px 0 0;
}

/* --- reviews ----------------------------------------------------------- */

.has-notes { margin: 0 0 18px; padding: 0; list-style: none; }

.has-notes li {
    border-left: 2px solid var(--line);
    padding: 0 0 0 12px;
    margin: 0 0 14px;
}

.has-notes .is-fineprint { margin-top: 4px; }

footer {
    border-top: 1px solid var(--line);
    margin-top: 20px;
}

/* --- places grid: the whole country inside one screen ------------------- */

/* Was a 38-row table, which pushed every advertisement below the fold. A visitor
   arriving needs the way forward without scrolling: where they are, which cities exist,
   and who is listed. Three columns fit all of them above the second screen. */
.has-places {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(190px, 100%), 1fr));
    gap: 0 22px;
    margin: 0 0 8px;
    padding: 0;
    list-style: none;
}

.has-places li {
    border-bottom: 1px solid var(--line);
    font-size: 15px;
}

/* The link IS the row — it carries the layout so the count and the space between are
   part of the target, not decoration sitting next to one. */
.has-places a {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 10px;
    padding: 6px 0;
    text-decoration: none;
    min-width: 0;
}

.has-places a:hover { background: var(--wash); }
.has-places a:hover span:first-child { text-decoration: underline; }

/* Takes the slack, so the footer below reaches the bottom of a short page. */
main.shell { flex: 1 0 auto; }
