/*
 * The site's one stylesheet, the administration's too. Mobile first: the base
 * rules are the phone's, wider screens only add room. Families use the site
 * on their phone every day (§5 of the brief), so 360 px is the width every
 * page is checked at.
 *
 * The direction ("Grand format", lot 5 bis): the families' photos carry the
 * colour, the page itself stays black and white. One high-contrast serif,
 * Gloock, for the headings only; Schibsted Grotesk for everything read. Both
 * are served by the site itself (`assets.ts`), nothing comes from elsewhere.
 * Every text colour below passes WCAG AA on the backgrounds it is used on.
 */

@font-face { font-family: 'Gloock'; src: url(/assets/gloock.woff2) format('woff2'); font-weight: 400; font-display: swap; unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: 'Schibsted Grotesk'; src: url(/assets/schibsted-grotesk.woff2) format('woff2'); font-weight: 400 900; font-display: swap; unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }

:root {
  --ink: #111111;
  --ink-soft: #3d3d3b;
  --muted: #676662;
  --paper: #ffffff;
  --soft: #f4f3f0;
  --line: #e4e2dd;
  /* The edge of a field or a control: 3.58:1 on the paper, 3.23:1 on the soft grey (WCAG 1.4.11 asks 3:1). */
  --line-strong: #8a8780;
  --ok: #24663a;
  --error: #a3301e;
  --ok-soft: #e8f2eb;
  --error-soft: #fbecea;
  --ok-line: #bcd9c4;
  --error-line: #efc4bc;
  --icon-check: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path d='M3.5 8.5l3 3 6-7' fill='none' stroke='white' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'/></svg>");
  --icon-trash: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M4 7h16M10 11v6M14 11v6M6 7l1 12a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2l1-12M9 7V4h6v3'/></svg>");
  --icon-cross: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.4' stroke-linecap='round'><path d='M6 6l12 12M18 6L6 18'/></svg>");
  --icon-photo: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linejoin='round'><rect x='3' y='4' width='18' height='16' rx='3'/><circle cx='9' cy='10' r='2'/><path d='M3 17l5-5 5 5 3-3 5 5'/></svg>");
  --radius: 18px;
  --radius-sm: 12px;
  --gutter: 16px;
  --display: 'Gloock', Georgia, 'Times New Roman', serif;
  --text: 'Schibsted Grotesk', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
  font-family: var(--text);
  color: var(--ink);
  background: var(--paper);
  line-height: 1.55;
  -webkit-text-size-adjust: 100%;
}

*, *::before, *::after { box-sizing: border-box; }
/* What a script hides stays hidden, whatever display its class gives it. */
[hidden] { display: none !important; }
body { margin: 0; min-height: 100vh; display: flex; flex-direction: column; background: var(--paper); }
main { flex: 1; }
img, svg { max-width: 100%; }
img { height: auto; }
a { color: var(--ink); text-underline-offset: 3px; }
h1, h2 { font-family: var(--display); font-weight: 400; line-height: 1.05; letter-spacing: -0.01em; text-wrap: balance; }
h3 { font-size: 1.05rem; font-weight: 700; line-height: 1.3; }
h1 { font-size: 2.3rem; margin: 0 0 14px; }
h2 { font-size: 1.6rem; margin: 0 0 10px; }
p { margin: 0 0 12px; }

.wrap { width: 100%; max-width: 1120px; margin: 0 auto; padding-inline: var(--gutter); }
.narrow { max-width: 520px; }

/* Off the screen above, not to a side: in Arabic, the side the page scrolls to. */
.skip { position: absolute; top: -9999px; inset-inline-start: var(--gutter); }
.skip:focus { top: 8px; z-index: 10; background: var(--paper); color: var(--ink); padding: 8px 12px; border-radius: 8px; }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
/* A word longer than the screen (a name typed without spaces, a link pasted in a remark) breaks rather than widen the page past a phone (defects D2, D13). */
h1, h2, h3, h4, strong, .facts dd, .notice, .prose { overflow-wrap: anywhere; }

/* Header: black on white; over the home page photo, white (`top-over`). */
.top { background: var(--paper); border-bottom: 1px solid var(--line); color: var(--ink); }
/* A header too long for its line wraps its links under the brand rather than run off the screen (audit A11Y-M2). */
.top .wrap { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 6px 10px; min-height: 64px; padding-block: 8px; }
.brand { display: inline-flex; align-items: center; gap: 8px; color: inherit; text-decoration: none; font-weight: 700; white-space: nowrap; }
.brand .mark { width: 26px; height: 26px; flex: none; }
/* The word in px, not rem: at 26 px its baseline falls on a whole pixel (brand/source/make.mjs). */
.brand:has(.brand-word) { gap: 10px; }
.brand:has(.brand-word) .mark { width: 30px; height: 30px; }
.brand-word { display: block; flex: none; font-size: 26px; overflow: visible; }
/* Gloock's hairlines are thinner than a pixel at this size and turn grey on a 1x screen: a 0.35 px
   outline makes them black again. A sharper screen draws them well and keeps the true drawing. */
.brand-word path { stroke: currentColor; stroke-width: 0.35px; stroke-linejoin: round; vector-effect: non-scaling-stroke; }
@media (min-resolution: 2dppx) { .brand-word path { stroke: none; } }
.nav { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 12px; }
/* On a phone, the catalogue and the institutions' page give way to the sign-in and the button: the home page names them under its search, every footer too. */
@media (max-width: 719px) { .nav .nav-more { display: none; } }
.nav a, .nav .btn { color: inherit; text-decoration: none; font-weight: 600; font-size: 0.92rem; white-space: nowrap; }
.nav a[aria-current="page"] { text-decoration: underline; text-underline-offset: 5px; }
.nav form { margin: 0; }
.top-over { position: absolute; inset: 0 0 auto 0; z-index: 2; background: transparent; border-bottom: 0; color: #ffffff; }
.top-over .nav a.btn-accent { background: #ffffff; color: var(--ink); }
.top-over .btn-ghost { color: #ffffff; border-color: rgba(255, 255, 255, 0.7); }
.top-over :focus-visible { outline-color: #ffffff; }

/* Buttons and forms */
.btn { display: inline-flex; align-items: center; justify-content: center; min-height: 48px; padding: 10px 22px; border-radius: 999px; border: 1.5px solid transparent; font: inherit; font-weight: 700; line-height: 1.2; text-align: center; text-decoration: none; cursor: pointer; }
.btn-sm { min-height: 38px; padding: 6px 15px; font-size: 0.9rem; }
.btn-accent { background: var(--ink); color: #ffffff; }
.btn-accent:hover { background: #333333; }
.nav a.btn-accent { color: #ffffff; }
.btn-ghost { background: transparent; border-color: var(--ink); color: var(--ink); }
.btn-ghost:hover { background: var(--soft); }
/* What deletes, removes, withdraws or refuses, always asked first: the error's red, 6.6:1 on white, so it is read before it is pressed. */
.btn-danger { background: transparent; border-color: var(--error); color: var(--error); }
.btn-danger:hover { background: var(--error-soft); }
/* A bin for what is deleted, a cross for a request withdrawn or refused. */
.btn-danger { gap: 8px; }
.btn-danger::before { content: ''; width: 18px; height: 18px; flex: none; background: currentColor; -webkit-mask: var(--icon-trash) center / contain no-repeat; mask: var(--icon-trash) center / contain no-repeat; }
.btn-danger.btn-cross::before { -webkit-mask-image: var(--icon-cross); mask-image: var(--icon-cross); }
.btn-sm.btn-danger::before { width: 16px; height: 16px; }
.btn-block { width: 100%; }
a:focus-visible, button:focus-visible, input:focus-visible, select:focus-visible, textarea:focus-visible, summary:focus-visible, [tabindex="0"]:focus-visible { outline: 3px solid var(--ink); outline-offset: 2px; }
button:disabled { opacity: 0.45; cursor: not-allowed; }

.form { display: grid; gap: 18px; }
.field { display: grid; gap: 6px; min-width: 0; }
.field label, .legend { font-weight: 700; font-size: 0.92rem; }
.field input:not([type]), .field input[type="email"], .field input[type="text"], .field input[type="password"], .field input[type="tel"], .field input[type="number"], .field input[type="date"], .field input[type="time"], .field select, .field textarea {
  width: 100%; min-width: 0; min-height: 48px; padding: 10px 14px; border: 1.5px solid var(--line-strong); border-radius: var(--radius-sm); background: var(--paper); font: inherit; color: var(--ink);
}
/* A number or an address typed in an Arabic page stays left to right, its groups in order; it still starts on the right like the rest. */
input[type="tel"], input[type="email"] { direction: ltr; }
[dir="rtl"] input[type="tel"], [dir="rtl"] input[type="email"] { text-align: right; }
/* A count of a few digits: a short field, not the width of an address. */
.field input[type="number"] { width: 7rem; }
/* A short field and its button on one line; the button goes under it on a screen too narrow. */
.field-row { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
.field textarea { resize: vertical; }
/* Audit MKT-C6: the institution's name only once "an institution" is chosen; without :has(), it stays shown. */
.form:has(input[name="role"]):not(:has(input[name="role"][value="institution"]:checked)) .field-institution { display: none; }
.field input[aria-invalid="true"], .field select[aria-invalid="true"], .field textarea[aria-invalid="true"] { border-color: var(--error); }
/*
 * A file to send (`fileField`): the browser's button speaks the browser's
 * language and says "no file chosen", so it is hidden from sight only, and
 * its label, a button in the page's words, opens the files; the keyboard
 * still reaches the input, whose focus is drawn on the button.
 */
.file-field { position: relative; }
.file-input { position: absolute; inset-inline-start: 0; bottom: 0; width: 1px; height: 1px; opacity: 0; }
.file-pick { justify-self: start; gap: 10px; }
/* A photo's button carries a picture; a document's (a PDF too) none. */
.file-input[accept="image/*"] + .file-pick::before { content: ''; width: 20px; height: 20px; flex: none; background: currentColor; -webkit-mask: var(--icon-photo) center / contain no-repeat; mask: var(--icon-photo) center / contain no-repeat; }
.file-input:focus-visible + .file-pick { outline: 2px solid var(--ink); outline-offset: 3px; }
.file-input[aria-invalid="true"] + .file-pick { border-color: var(--error); }
/* Empty, out of sight but still there: a live region shown only once it speaks is not heard by every screen reader (audit A11Y-m2). */
.file-chosen:empty { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
p[data-status]:empty { margin: 0; }
.file-chosen.error { color: var(--error); }
/* The photos chosen and not sent yet: as large as those kept (`.thumbs`), with a round cross on the corner. */
.thumbs.file-thumbs li { position: relative; }
.thumbs.file-thumbs .thumb-remove { position: absolute; top: 6px; inset-inline-end: 6px; width: 36px; min-height: 36px; height: 36px; padding: 0; border-radius: 50%; background: var(--paper); }
.thumbs.file-thumbs .thumb-remove:hover { background: var(--error-soft); }
fieldset { border: 0; padding: 0; margin: 0; display: grid; gap: 10px; min-width: 0; }
/*
 * The characters typed in a text that needs a minimum (`profile.js`): red
 * at first, turning to green as the text grows (`--progress`, 0 to 1),
 * through amber, all dark enough to read on white; a check once long enough.
 */
.char-count { justify-self: end; display: inline-flex; align-items: center; gap: 6px; font-size: 0.85rem; font-weight: 600; font-variant-numeric: tabular-nums; color: var(--error); color: color-mix(in oklch, var(--ok) calc(var(--progress, 0) * 100%), var(--error)); }
.char-count-ok { color: var(--ok); }
.char-count-ok::before { content: ''; width: 16px; height: 16px; border-radius: 50%; background: var(--ok) var(--icon-check) center / 11px no-repeat; }
/* The presentation in several languages (R32): each field after the first can go, and a list adds another. */
.intros { gap: 16px; }
.intro-remove { justify-self: start; }
.intro-add-row { display: flex; gap: 10px; }
.intro-add-row select { flex: 1; }
.choice { display: grid; grid-template-columns: auto 1fr; gap: 4px 12px; align-items: start; padding: 14px; border: 1.5px solid var(--line); border-radius: var(--radius-sm); background: var(--paper); cursor: pointer; }
.choice:has(input:checked) { border-color: var(--ink); }
.choice input { margin-top: 4px; width: 18px; height: 18px; accent-color: var(--ink); }
.choice .hint { grid-column: 2; color: var(--muted); font-size: 0.9rem; }
/* Choices as tags as wide as their words, so a long one ("Half board (breakfast and dinner)") is not squeezed into a narrow column over four lines. */
.picks { display: flex; flex-wrap: wrap; gap: 8px; }
.pick { flex: 0 1 auto; display: flex; align-items: flex-start; gap: 10px; padding: 12px 14px; border: 1.5px solid var(--line); border-radius: var(--radius-sm); background: var(--paper); cursor: pointer; font-weight: 400; }
.pick:has(input:checked) { border-color: var(--ink); }
.field .pick { font-weight: 400; font-size: 1rem; }
.pick input { margin: 3px 0 0; width: 18px; height: 18px; flex: none; accent-color: var(--ink); }
/* Short choices (languages) that stretch to fill their line, so both edges are straight and no tag is left alone with a hole beside it; the last line keeps its tags their own width. Equal columns would cut a long name (Portugiesisch, Португальский) in a narrow panel. */
.picks-fill { gap: 6px; }
.picks-fill::after { content: ""; flex: 999 1 0; }
.picks-fill .pick { flex: 1 1 auto; align-items: center; gap: 8px; padding: 9px 10px; }
.picks-fill .pick input { margin: 0; }
/* The languages past the eleven most students share, behind a button (audit TRA-M8). */
.picks-more { margin-top: 10px; }
.picks-more > summary { cursor: pointer; font-weight: 700; padding-block: 6px; }
.picks-more > .picks { margin-top: 8px; }
/* A choice that is a thing to pick (a room): one per line, its photo, then its name, a detail and its price, each on its own line. */
.pick-card { flex: 1 1 100%; align-items: center; padding: 10px 12px; }
.pick-card input { margin: 0; }
.pick-card:has(input:checked) { background: var(--soft); }
.pick-thumb { flex: none; width: 64px; height: 64px; border-radius: 8px; object-fit: cover; background: var(--soft); }
.pick-text { display: grid; gap: 1px; min-width: 0; line-height: 1.35; }
.pick-text .muted { font-size: 0.9rem; }
.pick-emphasis { font-weight: 700; }
.error { color: var(--error); font-weight: 600; font-size: 0.9rem; margin: 0; }
.ok { color: var(--ok); font-weight: 600; margin: 0; }
/* A page's answer to what was just sent (saved, refused): a band that catches the eye, unlike a field's error under its input. */
p.ok[role], p.error[role] { display: flex; align-items: center; gap: 12px; font-size: 1rem; line-height: 1.4; padding: 12px 18px 12px 12px; border: 1px solid; border-radius: var(--radius-sm); }
p.ok[role]::before, p.error[role]::before { content: ''; flex: none; width: 26px; height: 26px; border-radius: 50%; background: center / 16px no-repeat; }
p.ok[role] { background: var(--ok-soft); border-color: var(--ok-line); }
p.ok[role]::before { background-color: var(--ok); background-image: var(--icon-check); }
p.error[role] { background: var(--error-soft); border-color: var(--error-line); }
p.error[role]::before { background-color: var(--error); background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path d='M8 3.5v5.2' stroke='white' stroke-width='2.2' stroke-linecap='round'/><circle cx='8' cy='12.2' r='1.3' fill='white'/></svg>"); }
.badge { justify-self: start; display: inline-block; color: var(--ok); font-size: .85rem; font-weight: 600; border: 1px solid currentColor; border-radius: 999px; padding: 0 10px; }
.notice { background: var(--soft); border-radius: var(--radius-sm); padding: 12px 16px; margin: 0; }
.code { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 1.3rem; letter-spacing: 0.15em; }

/* Sign-up steps */
.steps { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.step { position: relative; display: grid; grid-template-columns: auto 1fr auto; gap: 12px; align-items: center; padding: 14px; border: 1.5px solid var(--line); border-radius: var(--radius-sm); background: var(--paper); }
/* The whole card opens the step: the title's link reaches over it, so a screen reader still hears the title alone. */
.step-body a::after { content: ''; position: absolute; inset: 0; }
.step:has(a:hover) { border-color: var(--ink); }
.step-body a:focus-visible { outline: none; }
.step:has(a:focus-visible) { outline: 3px solid var(--ink); outline-offset: 2px; }
.step-number { width: 30px; height: 30px; border-radius: 50%; display: grid; place-items: center; border: 1.5px solid var(--ink); font-weight: 700; font-size: 0.85rem; }
.step-done .step-number { background: var(--ink); color: #ffffff; }
.step-body { display: grid; gap: 2px; min-width: 0; }
.step-body a, .step-body > span:first-child { font-weight: 700; }
.step-status { font-size: 0.8rem; font-weight: 700; color: var(--muted); text-align: end; max-width: 6rem; }
.step-done .step-status { color: var(--ok); }
/* A step done shows a green check; the word stays for a screen reader. */
.step-check { width: 26px; height: 26px; border-radius: 50%; background: var(--ok) var(--icon-check) center / 16px no-repeat; }
.step-later { opacity: 0.7; }
.block { border-top: 1.5px solid var(--ink); padding-top: 18px; display: grid; gap: 12px; }
.block h2 { margin: 0; }
/* A block's heading with what acts on the whole block (withdraw a room) at its far right; a long name wraps, the button stays put. */
.block-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.block-head h2 { min-width: 0; overflow-wrap: break-word; }
.block-head form { flex: none; margin: 0; }
/* A room's photo with the code (R30), under its photos, set apart by a thin line. */
.code-photo { display: grid; gap: 12px; padding-top: 14px; border-top: 1px solid var(--line); }
.code-photo h3 { margin: 0; }
/* A button shown by its icon only, in a column too narrow for its words beside a heading: they stay for a screen reader and show on hover (`title`). */
.btn-icon { width: 38px; padding: 0; border-radius: 50%; }
.charter { margin: 0; padding-inline-start: 20px; display: grid; gap: 8px; }

/* Uploaded files */
.thumbs { list-style: none; margin: 0; padding: 0; display: grid; gap: 12px; grid-template-columns: repeat(2, minmax(0, 1fr)); }
.thumbs li { display: grid; gap: 6px; }
.thumbs img { display: block; width: 100%; aspect-ratio: 4 / 3; object-fit: cover; border-radius: var(--radius-sm); background: var(--line); }
.thumbs form, .rows form { margin: 0; }
/* The review of the administration: each photo whole in its box, never cut to it, and the small copy sent with it beside it, smaller (audit SEC-B6). The box keeps its room while the photo loads, so the page does not move under a click. */
.review-photos li { display: flex; gap: 6px; align-items: flex-start; }
.review-photos li > a { flex: 3 1 0; min-width: 0; }
.review-photos .thumb-copy { flex: 1 1 0; min-width: 0; }
.review-photos img { object-fit: contain; }
.rows { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.rows li { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px 12px; padding: 12px 14px; border: 1.5px solid var(--line); border-radius: var(--radius-sm); }
/* The text takes the room left and wraps itself, so the buttons stay at the right of every row; they go under it only below 8rem of text. A long address breaks rather than widening the page. */
.rows li > span { flex: 1 1 8rem; min-width: 0; overflow-wrap: anywhere; }
/* The messages of a request (lot 17), oldest first, the reader's own on a tinted ground. */
.messages { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }
.message { display: grid; gap: 6px; padding: 12px 14px; border: 1.5px solid var(--line); border-radius: var(--radius-sm); }
.message-own { background: var(--soft); }
.message p { margin: 0; }
.message form { margin: 0; justify-self: start; }

/* Pages */
.page { padding-block: 32px 56px; }
.card { background: var(--paper); border: 1.5px solid var(--line); border-radius: var(--radius); padding: 22px; }
.lead { font-size: 1.08rem; color: var(--ink-soft); max-width: 75ch; }
.muted { color: var(--muted); font-size: 0.92rem; }
.stack > * + * { margin-top: 16px; }
.stack > h2 { margin-top: 32px; }
.stack > h2:first-child { margin-top: 0; }
.prose { white-space: pre-line; overflow-wrap: anywhere; max-width: 65ch; }
/* The trail from the home page, above a public page's heading. */
.crumbs ol { list-style: none; margin: 0 0 12px; padding: 0; display: flex; flex-wrap: wrap; gap: 4px 8px; font-size: 0.92rem; }
.crumbs li { min-width: 0; overflow-wrap: anywhere; }
.crumbs li + li::before { content: "\203A"; margin-inline-end: 8px; color: var(--muted); }
[dir="rtl"] .crumbs li + li::before { content: "\2039"; }

/* Home: the photo, the search under it, then the three ways in. */
.hero { position: relative; min-height: 560px; display: grid; align-items: end; color: #ffffff; background: #2b2a28; }
.hero-photo { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
/* The veil under the white words: darker behind the header and the heading, measured on the photo itself (lot A12): 4.5:1 at the least behind the links, 3:1 behind the heading. */
.hero::after { content: ''; position: absolute; inset: 0; background: linear-gradient(180deg, rgba(0, 0, 0, 0.6) 0%, rgba(0, 0, 0, 0.5) 12%, rgba(0, 0, 0, 0.12) 24%, rgba(0, 0, 0, 0.5) 38%, rgba(0, 0, 0, 0.8) 100%); }
.hero-text { position: relative; z-index: 1; padding-block: 120px 32px; }
.hero h1 { font-size: clamp(2.5rem, 10.5vw, 5.4rem); line-height: 0.98; max-width: 14ch; margin: 0; }
/* What the site is, in the words a search finds (audit SEO-11), over the tagline that says it best. */
.hero-kicker { display: block; font-family: var(--text); font-size: 1rem; font-weight: 700; line-height: 1.3; letter-spacing: 0.02em; max-width: 40ch; margin-bottom: 14px; }
.hero .lead { color: #f1f0ec; margin: 16px 0 0; max-width: 46ch; }
.search { border-bottom: 1px solid var(--line); padding-block: 20px; }
.search-form { display: grid; grid-template-columns: minmax(0, 1fr); gap: 12px; }
.entries-band { background: var(--soft); padding-block: 48px; }
.entries-band h2 { font-size: clamp(2rem, 7vw, 3rem); margin-bottom: 20px; }
.entries { list-style: none; margin: 0; padding: 0; display: grid; }
.entry { display: flex; flex-direction: column; gap: 8px; padding: 22px 0; border-top: 1.5px solid var(--ink); }
.entry h3 { font-family: var(--display); font-weight: 400; font-size: 1.7rem; line-height: 1.1; margin: 0; }
.entry p { color: var(--ink-soft); margin: 0; max-width: 56ch; }
.entry a { font-weight: 700; }
.entry .entry-links { display: flex; flex-wrap: wrap; gap: 6px 18px; margin-top: auto; padding-top: 6px; }
/* Under the home page's search, the pages for institutions and families (audit MKT-A3). */
.search-more { display: flex; flex-wrap: wrap; gap: 6px 18px; margin-top: 14px; font-weight: 700; }
/* What a visitor can count on (audit MKT-E3): three short lines, each with its drawing. */
.trust { list-style: none; margin-block: 16px 0; display: flex; flex-wrap: wrap; gap: 8px 28px; color: var(--ink-soft); font-size: 0.92rem; }
.trust li { display: flex; align-items: center; gap: 8px; min-width: 0; }
.trust svg { width: 20px; height: 20px; flex: none; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
/* The steps and the lists of a presentation page (`presentation-pages.ts`). */
.points { margin: 0; padding-inline-start: 1.4em; display: grid; gap: 8px; }
.entry .soon { color: var(--muted); font-weight: 600; margin-top: auto; }

/* City pages */
.city-page h1 { overflow-wrap: break-word; }
.city-page h2 { margin-top: 36px; }
.city-more { margin: 40px 0 0; text-align: center; }
.city-links { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 8px 24px; }
.city-links a { font-weight: 700; }
.city-study { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; }
.city-study bdi { font-weight: 600; }
.cities-band { padding: 32px 0 48px; }
.cities-band h2 { margin-bottom: 16px; }

/* Administration */
.figures { display: grid; gap: 12px; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); margin-top: 16px; }
.figure { font-family: var(--display); font-size: 2.4rem; line-height: 1; margin: 0; }
.facts { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: 10px 24px; margin: 0; }
.facts dt { color: var(--muted); }
.facts dd { margin: 0; font-weight: 600; overflow-wrap: anywhere; }
.table-scroll { overflow-x: auto; margin-top: 12px; }
.table { width: 100%; border-collapse: collapse; background: var(--paper); font-size: 0.92rem; }
.table th, .table td { text-align: start; padding: 10px 12px; border-bottom: 1px solid var(--line); vertical-align: top; }
.table thead th { border-bottom: 1.5px solid var(--ink); }
.table caption { text-align: start; font-weight: 700; padding: 0 0 8px; }
.table .num { text-align: end; white-space: nowrap; }
.table tr.total th, .table tr.total td { font-weight: 700; }
/* Lot B17: who issued a receipt and who paid it, side by side when they fit. */
.receipt-parties { display: grid; grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr)); gap: 16px; }
.receipt-parties h2 { font-size: 1rem; margin-bottom: 4px; }
.table input[type="text"] { width: 6.5em; min-height: 36px; padding: 4px 8px; border: 1.5px solid var(--line-strong); border-radius: 8px; background: var(--paper); font: inherit; color: var(--ink); }
.tabs { display: flex; flex-wrap: wrap; gap: 8px; margin: 12px 0; }
.tabs a { padding: 7px 14px; border: 1.5px solid var(--line); border-radius: 999px; text-decoration: none; color: var(--ink); font-size: 0.9rem; font-weight: 600; }
.tabs a[aria-current="page"] { background: var(--ink); border-color: var(--ink); color: #ffffff; }
.inline-form { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 6px; margin: 4px 0 0; }
.inline-form input[type="date"] { min-height: 36px; padding: 4px 8px; border: 1.5px solid var(--line-strong); border-radius: 8px; font: inherit; }
.check-row { display: grid; gap: 6px; }
.check-row input[type="text"] { min-height: 40px; padding: 8px 10px; border: 1.5px solid var(--line-strong); border-radius: 8px; font: inherit; }
.check-row .pick { padding: 8px 12px; }
.check-note { display: grid; gap: 2px; }
.check-note label { font-size: 0.85rem; color: var(--muted); }
.checklist { gap: 10px; }
.admin h3 { margin: 16px 0 8px; font-size: 1rem; }
/* A button of the administration is as wide as its words, not as the form. */
.admin .form > .btn { justify-self: start; }
/* A photo to check is opened in full: the page shows small ones, several to a line. */
.admin .thumbs { grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); }
/* A family's page is long: its links to the sections stay at the top of the screen, and a section reached by one is not hidden under them. */
.family-jump { position: sticky; top: 0; z-index: 10; flex-wrap: nowrap; overflow-x: auto; margin: 20px 0 0; padding-block: 10px; background: var(--paper); border-bottom: 1px solid var(--line); }
/* One line, scrolled sideways on a phone: three lines of links would hide the section they lead to. */
.family-jump a { flex: none; white-space: nowrap; }
.family-section { scroll-margin-top: 72px; }
/* Nor is a field reached by the keyboard (audit A11Y-m12). */
html:has(.family-jump) { scroll-padding-top: 72px; }
.admin main .family-section > h2:first-child { margin-top: 0; }
.admin main section.family-section { margin-top: 40px; }
/* A section's title stands apart from the table or the cards above it. */
.admin main h2 { margin-top: 32px; }
.admin .brand { font-size: 1.05rem; }

/* Catalogue */
.narrow-wide { max-width: 800px; }
.dates { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 10px; }
.dates input[type="date"] { padding-inline: 10px; }
.filters { display: grid; gap: 16px; align-content: start; }
.filters details { border-top: 1px solid var(--line); padding-top: 14px; }
.filters summary { cursor: pointer; font-weight: 700; min-height: 32px; text-decoration: underline; text-underline-offset: 4px; }
.filters details[open] summary { margin-bottom: 14px; }
.change-dates summary { cursor: pointer; min-height: 32px; text-decoration: underline; text-underline-offset: 4px; }
.change-dates[open] summary { margin-bottom: 14px; }
/* A secret saved (the tax number): masked, in a box the size of the field it came from, a green badge, the field to replace it folded under. */
.saved-value { display: flex; align-items: center; gap: 12px; min-height: 48px; margin: 0; padding: 10px 14px; border: 1.5px solid var(--line); border-radius: var(--radius-sm); background: var(--soft); font-variant-numeric: tabular-nums; letter-spacing: 0.08em; }
.saved-badge { display: inline-flex; align-items: center; gap: 6px; margin-inline-start: auto; color: var(--ok); font-weight: 600; font-size: 0.88rem; letter-spacing: 0; }
.saved-badge::before { content: ''; width: 16px; height: 16px; border-radius: 50%; background: var(--ok) var(--icon-check) center / 11px no-repeat; }
.replace-value summary { cursor: pointer; justify-self: start; min-height: 32px; font-size: 0.92rem; text-decoration: underline; text-underline-offset: 4px; }
.replace-value[open] summary { margin-bottom: 10px; }
.actions { display: flex; flex-wrap: wrap; gap: 10px; }
.catalogue { display: grid; gap: 28px; margin-top: 20px; }
.results { display: grid; gap: 16px; align-content: start; min-width: 0; }
.count { margin: 0; font: inherit; font-weight: 700; }
.families { list-style: none; margin: 0; padding: 0; display: grid; row-gap: 2px; }
/* The cards of a row read alike: each line of a card (name, place, meals, languages, rating, price) shares its height with the
   same line of the cards beside it, and the badge sits on the photo, so a long name or a meal plan on two lines shifts nothing. */
.families > li { display: grid; grid-row: span 7; grid-template-rows: subgrid; padding-bottom: 30px; }
.family-card-box { position: relative; display: grid; grid-row: span 7; grid-template-rows: subgrid; color: var(--ink); }
/* The name is the only link; stretched over the card, the whole card is still one tap to the room. */
.family-card { color: inherit; text-decoration: none; }
.family-card::after { content: ''; position: absolute; inset: 0; border-radius: 14px; }
.family-card:focus-visible { outline: none; }
.family-card-box:has(.family-card:focus-visible) { outline: 2px solid var(--ink); outline-offset: 4px; border-radius: 14px; }
.family-card-media { position: relative; }
.family-card-media .badge { position: absolute; top: 12px; inset-inline-start: 12px; background: var(--paper); border-color: transparent; padding: 2px 10px; }
.cover { display: block; width: 100%; height: auto; aspect-ratio: 4 / 5; object-fit: cover; border-radius: 14px; background: var(--soft); margin-bottom: 10px; }
.family-card-box:hover .cover { opacity: 0.92; }
.family-card-body { display: contents; }
.family-card-extra { display: grid; gap: 2px; align-content: start; }
.family-card-name { margin: 0; font-family: var(--display); font-weight: 400; font-size: 1.5rem; line-height: 1.1; }
.family-card-box:hover .family-card { text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 4px; }
.price { font-weight: 700; margin: 6px 0 0; }
/* Lot 15: each criterion of the student set against a family, said in words; the mark only repeats it, a tick or a cross. */
.match-count { font-weight: 600; margin-top: 4px; }
.matches { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.match-point { display: flex; align-items: center; gap: 8px; }
.match-point::before { content: ''; flex: none; width: 16px; height: 16px; border-radius: 50%; background: var(--ok) var(--icon-check) center / 11px no-repeat; }
.match-miss { color: var(--error); }
.match-miss::before { border-radius: 0; background: currentColor; -webkit-mask: var(--icon-cross) center / 12px no-repeat; mask: var(--icon-cross) center / 12px no-repeat; }
.pager { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.more-button { justify-self: center; }

/* A family's page: the photos first, the facts a student weighs under them, then the house section by section, beside the dates and the request. */
.family-head { display: grid; gap: 8px; }
.family-head h1 { margin: 0; font-size: clamp(2.6rem, 11vw, 4.6rem); line-height: 0.98; overflow-wrap: break-word; }
.family-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 16px; margin: 0; color: var(--ink-soft); }
.badge-pending { color: var(--ink-soft); }
/* On a phone the photos are swiped from edge to edge; the next one shows at the side, so the eye knows there are more. */
.mosaic, .gallery { list-style: none; padding: 0; display: flex; gap: 6px; overflow-x: auto; scroll-snap-type: x mandatory; scrollbar-width: thin; }
.mosaic { margin: 24px calc(-1 * var(--gutter)) 0; padding-inline: var(--gutter); scroll-padding-inline: var(--gutter); }
.gallery { margin: 0; }
.mosaic li, .gallery li { flex: 0 0 86%; scroll-snap-align: start; min-width: 0; }
.mosaic li:only-child, .gallery li:only-child { flex-basis: 100%; }
.mosaic img, .gallery img { display: block; width: 100%; height: auto; aspect-ratio: 4 / 3; object-fit: cover; border-radius: 10px; background: var(--soft); }
/* A label above its value, each pair under a thin line: read at a glance, two or four to a line on a wider screen. */
.spec { display: grid; grid-template-columns: minmax(0, 1fr); column-gap: 32px; margin: 0; }
.spec > div { min-width: 0; padding: 12px 0; border-top: 1px solid var(--line); }
.spec dt { color: var(--muted); font-size: 0.88rem; }
.spec dd { margin: 2px 0 0; font-weight: 600; overflow-wrap: anywhere; }
.spec-band { margin-top: 24px; grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: 20px; border-bottom: 1px solid var(--line); }
.profile { display: grid; gap: 40px; margin-top: 32px; }
.profile-main { min-width: 0; }
.profile-side { min-width: 0; display: grid; gap: 14px; align-content: start; }
.profile-side .card { box-shadow: 0 12px 32px rgba(0, 0, 0, 0.07); }
.book, #request { scroll-margin-top: 16px; }
.book-price { font-size: 1.7rem; margin: 0; }
/* Each part of the house opens under a black rule, as in a magazine. */
.family-block { margin-top: 36px; padding-top: 22px; border-top: 1px solid var(--ink); }
.profile-main > :first-child { margin-top: 0; }
.family-block > * { margin: 0; }
.family-block > * + * { margin-top: 14px; }
.about { font-size: 1.15rem; line-height: 1.6; }
/*
 * The map of the home's area (`home-maps.ts`): OpenStreetMap's tiles laid
 * around the centre, the only images the site takes from elsewhere. Never
 * scrolled or zoomed; a phone sees its middle. Not mirrored in Arabic: a map
 * has no reading direction. A pin carries the number of its place in the lists.
 * Every screen sees the same 640 by 320 pixels of tiles, those whose places
 * are numbered (`catalogue-pages.ts`): a narrower one shrinks the map, not its
 * pins, by steps (a ratio of lengths is not yet computed by every browser).
 */
.area-map { margin: 18px 0 0; container-type: inline-size; }
.area-map-view { --map-scale: 1; position: relative; height: calc(320px * var(--map-scale)); overflow: hidden; border-radius: var(--radius-sm); background: var(--soft); }
@container (max-width: 639px) { .area-map-view { --map-scale: 0.85; } }
@container (max-width: 543px) { .area-map-view { --map-scale: 0.7; } }
@container (max-width: 447px) { .area-map-view { --map-scale: 0.55; --pin-size: 0.84; } }
@container (max-width: 351px) { .area-map-view { --map-scale: 0.5; } }
@container (max-width: 319px) { .area-map-view { --map-scale: 0.45; } }
.area-map-layer { position: absolute; left: 50%; top: 50%; width: 0; height: 0; scale: var(--map-scale); }
.area-map-layer .tile { position: absolute; width: 256px; height: 256px; max-width: none; }
.area-circle { position: absolute; border-radius: 50%; border: calc(2px / var(--map-scale)) solid var(--ink); background: rgb(17 17 17 / 0.14); }
/* Three colours apart in hue, each with white numbers readable on it; the number trimmed to its digits, so that it sits in the middle of its circle. */
.pin { display: inline-grid; place-items: center; width: 24px; height: 24px; border-radius: 50%; border: 2px solid #ffffff; background: #1d4ed8; color: #ffffff; font-size: 0.72rem; font-weight: 700; line-height: 1; font-variant-numeric: lining-nums tabular-nums; }
.pin > span { text-box: trim-both cap alphabetic; }
.pin-study { background: #047857; }
.pin-leisure { background: #c2410c; }
/* A place too far for the map keeps its colour in the list, without a number. */
.pin-off { width: 12px; height: 12px; margin: 6px; border: 0; }
.area-map-layer .pin { position: absolute; transform: translate(-50%, -50%) scale(calc(var(--pin-size, 1) / var(--map-scale))); box-shadow: 0 1px 3px rgb(0 0 0 / 0.35); }
.area-map-credit { margin-top: 6px; font-size: 0.78rem; color: var(--muted); text-align: end; }
.area-map-credit a { color: inherit; }
.nearby-groups { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 20px; }
.nearby-groups h3 { margin: 0; }
.nearby-list { list-style: none; padding: 0; margin: 10px 0 0; display: grid; gap: 10px; }
.nearby-list li { display: grid; grid-template-columns: 24px minmax(0, 1fr); column-gap: 10px; align-items: start; }
.nearby-list .pin { grid-row: span 2; }
.nearby-name { font-weight: 600; overflow-wrap: anywhere; }
.nearby-list .muted { grid-column: 2; font-size: 0.9rem; }
/* A group of photos: each one opens the window of all of them (`photos.js`); its button, there once the script runs, sits on the photos' corner. */
.photos { position: relative; }
.photos a[data-photo] { display: block; height: 100%; border-radius: 10px; cursor: pointer; }
.photos a[data-photo]:hover img { opacity: 0.92; }
.photos-all { position: absolute; bottom: 14px; inset-inline-end: 14px; background: var(--paper); color: var(--ink); border-color: var(--ink); box-shadow: 0 6px 18px rgba(0, 0, 0, 0.18); }
.photos-all:hover { background: var(--soft); }
.family-block .photos-all { bottom: 18px; }
/* The rooms of a home, one to a line, each one tap to its own page. */
.room-links { list-style: none; padding: 0; display: grid; gap: 12px; }
.family-block > .room-links { margin-top: 20px; }
.room-link { display: grid; grid-template-columns: 112px minmax(0, 1fr); gap: 14px; align-items: center; padding: 10px; color: var(--ink); text-decoration: none; border: 1.5px solid var(--line); border-radius: var(--radius-sm); }
.room-link:hover { border-color: var(--ink); }
.room-cover { display: block; width: 100%; aspect-ratio: 4 / 3; object-fit: cover; border-radius: 8px; background: var(--soft); }
.room-link-body { display: grid; gap: 2px; min-width: 0; }
.room-link-body strong { font-family: var(--display); font-weight: 400; font-size: 1.4rem; line-height: 1.1; overflow-wrap: anywhere; }
.room-link:hover strong { text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 4px; }
.room-link .price { margin-top: 4px; }
/* What is in a room: a short list in columns, each item under a thin line. */
.amenities { list-style: none; padding: 0; columns: 2; column-gap: 24px; }
.amenities li { padding: 7px 0; border-bottom: 1px solid var(--line); break-inside: avoid; }
.room-page .family-block .gallery { margin-top: 18px; }
/* The photos' window: the photo as large as the screen allows, on black; swiped on a phone, turned by two buttons on a wider screen. */
html:has(dialog.viewer[open]) { overflow: hidden; }
.viewer { width: 100vw; height: 100dvh; max-width: none; max-height: none; margin: 0; padding: 0; border: 0; background: #0d0d0c; color: #ffffff; }
.viewer::backdrop { background: rgba(0, 0, 0, 0.9); }
.viewer[open] { display: grid; grid-template-rows: auto minmax(0, 1fr); }
.viewer-head { display: flex; align-items: center; gap: 16px; padding: 10px var(--gutter); }
.viewer-title { flex: 1; min-width: 0; margin: 0; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.viewer-counter { margin: 0; color: #d6d3cc; font-variant-numeric: tabular-nums; }
.viewer-close { flex: none; width: 44px; height: 44px; padding: 0; border: 1.5px solid rgba(255, 255, 255, 0.6); border-radius: 50%; background: transparent; color: #ffffff; font: inherit; font-size: 1.6rem; line-height: 1; cursor: pointer; }
.viewer-track { list-style: none; margin: 0; padding: 0; display: flex; overflow-x: auto; scroll-snap-type: x mandatory; scrollbar-width: none; overscroll-behavior: contain; }
.viewer-track li { flex: 0 0 100%; min-width: 0; scroll-snap-align: start; display: flex; align-items: center; justify-content: center; padding: 0 var(--gutter) var(--gutter); }
/* The window's head is 64 px high: the photo takes what is left of the screen, never more. */
.viewer-track img { display: block; max-width: 100%; max-height: calc(100dvh - 64px - var(--gutter)); object-fit: contain; border-radius: 6px; }
/* At every width, 44 px on a phone: swiping is not the only way through the photos (audit A11Y-m5). */
.viewer-step { display: grid; place-items: center; z-index: 1; position: absolute; top: 50%; translate: 0 -50%; width: 44px; height: 44px; padding: 0; border: 0; border-radius: 50%; background: rgba(255, 255, 255, 0.92); color: var(--ink); font: inherit; font-size: 2rem; line-height: 1; cursor: pointer; }
.viewer-step:disabled { opacity: 0.3; cursor: default; }
.viewer-previous { inset-inline-start: 18px; }
.viewer-next { inset-inline-end: 18px; }
[dir="rtl"] .viewer-step { scale: -1 1; }
.viewer button:focus-visible { outline: 3px solid #ffffff; outline-offset: 2px; }
/* A room taken for the dates asked stays shown, its photos faded. */
.room-taken img { opacity: 0.55; filter: grayscale(1); }
/* On a phone the request comes after the whole page: a bar at the bottom of the screen leads to it, and stops above the footer. */
.family-page { padding-bottom: 0; }
.book-bar { position: sticky; bottom: 0; z-index: 15; display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-top: 40px; padding: 10px var(--gutter) calc(10px + env(safe-area-inset-bottom)); background: var(--paper); border-top: 1px solid var(--line); box-shadow: 0 -8px 24px rgba(0, 0, 0, 0.06); }
.book-bar p { margin: 0; }
/* A field or a link reached by the keyboard is never left under the bar (audit A11Y-M1); the bar is gone from 960 px. */
@media (max-width: 959px) { html:has(.book-bar) { scroll-padding-bottom: 88px; } }
.links { list-style: none; margin: 0; padding: 16px 0 0; border-top: 1px solid var(--line); display: grid; gap: 10px; }
.table-scroll + .links { border-top: 0; padding-top: 0; }
.links a { font-weight: 700; }

/* Footer */
.footer { border-top: 1.5px solid var(--ink); background: var(--paper); color: var(--ink); font-size: 0.9rem; }
.footer .wrap { display: grid; gap: 18px; padding-block: 28px; }
.footer-tagline { font-family: var(--display); font-size: clamp(1.7rem, 7vw, 3rem); line-height: 1.05; margin: 0; }
.footer-row { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 10px 24px; }
.footer-links { display: flex; flex-wrap: wrap; gap: 6px 18px; }
.footer-legal { padding-top: 14px; border-top: 1px solid var(--line); font-size: 0.85rem; }
.footer-legal a { color: var(--muted); }
.footer-version { color: var(--muted); }
/* Ten languages go to the line rather than widen a narrow screen, text spacing enlarged (audit A11Y-4). */
.lang { display: flex; flex-wrap: wrap; gap: 4px 10px; }
.lang a { color: var(--muted); text-transform: uppercase; font-weight: 700; text-decoration: none; }
.lang a[aria-current="page"] { color: var(--ink); text-decoration: underline; text-underline-offset: 4px; }
.admin .footer .wrap { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 10px 24px; }
/* The administration's thirteen links never fit one line on a phone, nor on a narrow window: they wrap. */
.admin .top .wrap { flex-wrap: wrap; padding-block: 10px; }
.admin .nav { flex-wrap: wrap; gap: 8px 14px; }

/* A phone narrower than most: the header keeps to one line. */
@media (max-width: 400px) {
  .top .wrap { gap: 8px; }
  .brand, .brand:has(.brand-word) { gap: 6px; }
  .brand .mark, .brand:has(.brand-word) .mark { width: 22px; height: 22px; }
  .brand-word { font-size: 17px; }
  .nav { gap: 6px; }
  .nav a, .nav .btn-sm { font-size: 0.85rem; }
  .nav .btn-sm { padding-inline: 10px; }
  /* Signed in, the two links are longer: the door alone stands for the name, which the link still carries. */
  .top:has(.nav form) .brand-word { display: none; }
  .card { padding: 18px; }
}

/* The search fields (`search.js`): the city's suggestions, the dates' calendar. Without the script, a text field and two date fields. */
.combo, .range { position: relative; }
.combo-list { position: absolute; top: 100%; inset-inline: 0; z-index: 20; margin: 6px 0 0; padding: 6px; list-style: none; background: var(--paper); border: 1.5px solid var(--ink); border-radius: var(--radius-sm); box-shadow: 0 12px 32px rgba(0, 0, 0, 0.12); }
.combo-list [role="option"] { padding: 10px 12px; border-radius: 8px; cursor: pointer; }
.combo-list [aria-selected="true"], .combo-list [role="option"]:not([aria-disabled]):hover { background: var(--soft); }
/* The option the arrows are on: its grey alone is 1.1:1 against the list, the outline is what shows it. */
.combo-list [aria-selected="true"] { outline: 2px solid var(--ink); outline-offset: -2px; }
.combo-list .combo-none { color: var(--muted); cursor: default; }
/* A legend is not spaced like a label by the grid: the same 6 px by hand, so both fields line up. */
.range > legend { margin-bottom: 6px; }
.range-button { width: 100%; min-height: 48px; padding: 10px 14px; border: 1.5px solid var(--line-strong); border-radius: var(--radius-sm); background: var(--paper); font: inherit; color: var(--ink); text-align: start; cursor: pointer; }
.range-button.is-empty { color: var(--muted); }
.range-button[aria-expanded="true"] { border-color: var(--ink); }
.range-panel { position: absolute; top: 100%; inset-inline-start: 0; z-index: 20; width: 100%; margin-top: 6px; padding: 14px; display: grid; gap: 12px; background: var(--paper); color: var(--ink); border: 1.5px solid var(--ink); border-radius: var(--radius); box-shadow: 0 16px 40px rgba(0, 0, 0, 0.16); }
.range-head { position: absolute; top: 14px; inset-inline: 14px; display: flex; justify-content: space-between; pointer-events: none; }
.range-step { pointer-events: auto; width: 40px; height: 40px; display: grid; place-items: center; padding: 0; border: 1.5px solid var(--line-strong); border-radius: 50%; background: var(--paper); font: inherit; font-size: 1.4rem; line-height: 1; color: var(--ink); cursor: pointer; }
.range-months { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); gap: 24px; }
.range-month { width: 100%; border-collapse: collapse; table-layout: fixed; }
.range-month caption { font-weight: 700; line-height: 40px; margin-bottom: 6px; }
.range-month caption::first-letter { text-transform: uppercase; }
.range-month th { padding-bottom: 6px; font-size: 0.75rem; font-weight: 600; color: var(--muted); }
.range-month td { padding: 1px 0; }
.range-day { display: block; width: 100%; aspect-ratio: 1; max-height: 44px; padding: 0; border: 0; border-radius: 50%; background: none; font: inherit; font-size: 0.92rem; color: var(--ink); cursor: pointer; }
.range-day:not([aria-disabled]):hover { box-shadow: inset 0 0 0 1.5px var(--ink); }
.range-day[aria-disabled="true"] { color: #a9a7a1; text-decoration: line-through; cursor: default; }
/* The grey alone is 1.1:1 on white: a line above and below at 3.6:1 draws the stay (audit A11Y-m11). */
.range-day.in-range { background: var(--soft); border-radius: 0; box-shadow: inset 0 1.5px 0 var(--line-strong), inset 0 -1.5px 0 var(--line-strong); }
.range-day.is-edge { background: var(--ink); color: #ffffff; }
.range-status { margin: 0; font-size: 0.92rem; color: var(--ink-soft); }
.range-actions { display: flex; justify-content: space-between; gap: 12px; }

/* On a phone, a label above its value: a long label would squeeze the value into a sliver. */
@media (max-width: 719px) {
  .facts { grid-template-columns: minmax(0, 1fr); gap: 0; }
  .facts dd { margin-bottom: 12px; }
}

@media (min-width: 720px) {
  h1 { font-size: 3rem; }
  h2 { font-size: 1.9rem; }
  .page { padding-block: 48px 72px; }
  .hero { min-height: 660px; }
  .hero-text { padding-block: 160px 56px; }
  .search-form { position: relative; grid-template-columns: minmax(0, 1fr) minmax(0, 1.4fr) auto; align-items: end; }
  /* On the home page the calendar opens under the whole search, from its starting edge: it stays on the screen. */
  .search-form .range { position: static; }
  .search-form .range-panel { inset-inline-start: var(--gutter); }
  .range-panel { width: 640px; max-width: calc(100vw - 2 * var(--gutter)); }
  .entries { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 0 32px; }
  .families { grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: 24px; }
  .thumbs { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .admin .thumbs { grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); }
  /* A point of a checklist and its note on one line. */
  .check-row { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); align-items: center; }
  /* The home's photos as one mosaic around the first: two, three, four, or the first beside four, the others under them. */
  .mosaic { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 8px; margin-inline: 0; padding: 0; overflow: visible; }
  .mosaic img { border-radius: 6px; }
  .mosaic li:first-child { grid-column: span 2; grid-row: span 2; }
  .mosaic li:first-child img, .mosaic-4 li:last-child img { height: 100%; aspect-ratio: auto; }
  .mosaic-1 { grid-template-columns: minmax(0, 1fr); }
  .mosaic-1 li:first-child { grid-column: auto; grid-row: auto; }
  .mosaic-1 li:first-child img { aspect-ratio: 16 / 9; max-height: 560px; }
  .mosaic-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .mosaic-2 li:first-child { grid-column: auto; grid-row: auto; }
  .mosaic-2 li:first-child img { aspect-ratio: 4 / 3; }
  .mosaic-3 { grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); }
  .mosaic-3 li:first-child { grid-column: auto; }
  .mosaic-4 li:last-child { grid-column: span 2; }
  .spec { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .spec-band { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .room-link { grid-template-columns: 220px minmax(0, 1fr); gap: 22px; }
  .amenities { columns: 3; }
  /* Once the script opens them all in its window, the mosaic shows five photos; its button says how many there are. */
  .photos-ready .mosaic li:nth-child(n + 6) { display: none; }
  .viewer-step { width: 52px; height: 52px; }
  .viewer-track li { padding-inline: 88px; }
  .room-page .family-block .gallery li { flex-basis: 48%; }
}

@media (min-width: 960px) {
  .catalogue { grid-template-columns: 300px minmax(0, 1fr); align-items: start; gap: 40px; }
  .filters .dates { grid-template-columns: minmax(0, 1fr); }
  .families { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .profile { grid-template-columns: minmax(0, 1fr) 380px; align-items: start; gap: 56px; margin-top: 40px; }
  /* Short (dates still to choose), the request stays in view beside the house; a form to fill scrolls with the page. */
  .profile-side.is-sticky { position: sticky; top: 24px; }
  /* The calendar is wider than the column: it opens towards the page, not off the screen. */
  .book .range-panel { inset-inline-start: auto; inset-inline-end: 0; }
  .family-page { padding-bottom: 72px; }
  .book-bar { display: none; }
}

@media (prefers-reduced-motion: no-preference) {
  .cover, .btn { transition: opacity 0.15s, background-color 0.15s; }
  p.ok[role], p.error[role] { animation: arrive 0.9s ease-out; }
  @keyframes arrive { from { opacity: 0; transform: translateY(-4px); } }
}

/* The contract and the emergency sheet print from the browser (R11, R25): the page alone, without the site around it. */
@media print {
  .top, .footer, .skip, .no-print { display: none !important; }
  body { background: #fff; }
  .card { border: 0; box-shadow: none; padding: 0; }
}
