@font-face{font-family:'Barlow Condensed';font-style:normal;font-weight:400;font-display:swap;src:url(/fonts/barlowcondensed-400-latin.woff2) format('woff2')}
@font-face{font-family:'Barlow Condensed';font-style:normal;font-weight:600;font-display:swap;src:url(/fonts/barlowcondensed-600-latin.woff2) format('woff2')}
@font-face{font-family:'Barlow Condensed';font-style:normal;font-weight:700;font-display:swap;src:url(/fonts/barlowcondensed-700-latin.woff2) format('woff2')}
@font-face{font-family:'Barlow Semi Condensed';font-style:normal;font-weight:400;font-display:swap;src:url(/fonts/barlowsemicondensed-400-latin.woff2) format('woff2')}
@font-face{font-family:'Barlow Semi Condensed';font-style:normal;font-weight:600;font-display:swap;src:url(/fonts/barlowsemicondensed-600-latin.woff2) format('woff2')}
/* Metric-matched fallbacks. MEASURED with a canvas probe on a 69-character
   sample at 100 px, in the browser, against the three faces a Mac actually
   falls back to. Condensed faces are far narrower than the grotesque the system
   substitutes: Barlow Condensed 700 sets 2 757,80 px against Helvetica Neue's
   3 627,50 — 24,0 % narrower — and Barlow Semi Condensed 400 sets 2 930,10
   against 3 425,30, 14,5 % narrower. An unadjusted fallback therefore paints
   the page far too wide and every heading reflows when the real face lands,
   which is the whole CLS budget. Barlow's own box is 1000/-200 on a 1000 upem,
   hence 100 % over 20 % exactly on both. Re-measure rather than recompute if a
   face changes. */
@font-face{font-family:'Barlow Condensed Repli';src:local('Helvetica Neue'),local('Helvetica'),local('Arial');size-adjust:76%;ascent-override:100%;descent-override:20%;line-gap-override:0%}
@font-face{font-family:'Barlow Semi Condensed Repli';src:local('Helvetica Neue'),local('Helvetica'),local('Arial');size-adjust:85.5%;ascent-override:100%;descent-override:20%;line-gap-override:0%}

:root{
/* The one lighter surface in the system: a field, a dropdown, a filled chip.
   Never a card — there are no cards here. */
--carte:#f3f5f2;
/* Two rules and only two: ink between structures, a dashed grey inside one.
   The dashed line is the sheet's own convention; a solid grey would read as a
   weak version of the ink rule instead of a different kind of division. */
--ligne:#a8b2ab;
--ligne-2:rgba(22,33,28,.14);
--encre:#16211c;
--titre:#16211c;
--ink-2:#34453c;
/* MEASURED on the ground (#e9ece7), the field (#f3f5f2) and the ink footer:
   6,13 / 6,66 / 2,27. The first two are what matter — this grey never sits on
   the footer. Any replacement must clear 4,5 on both light grounds. */
--ink-3:#4a5a52;
/* Direction, not judgement: above the reference is the slate green that already
   means "quantity" here, below it is the one warm contrast the palette owns.
   MEASURED on the ground: 6,17 and 5,69. */
--hausse:#2c5f4f;
/* Deepened from #8a4a2c. MEASURED: at that value the two directional colours
   were 1,08:1 apart, and 1,11 / 1,22 under simulated protanopia and
   deuteranopia — one colour, to a dichromat, on two figures of identical size
   and weight. This clears 11,70:1 on the ground and 1,90 against the green,
   1,69 under deuteranopia and 2,31 under protanopia.
   It is the crimson of the sibling water site (its --grave, #6d030c), taken two
   steps darker: MEASURED, #6d030c itself separates from the green by only 1,48
   under deuteranopia and 1,57 under tritanopia — WORSE than the red-brown it
   replaced, because a pure red loses more luminance than a warm brown for the
   two commonest dichromacies. #5c0a10 keeps the crimson and the separation.
   That is close to the CEILING, and the ceiling is the point: two colours that
   must both clear 4,5:1 on this ground can be at most 3,91:1 apart, and only if
   one of them is pure black. Colour cannot carry this distinction at all, which
   is why the direction is stated in words directly under every delta and the
   hue is only the echo. */
--baisse:#5c0a10;
--bord:#b4bdb6;
/* The millimetric ground. 13 px at 5,5 % ink: visible as a texture, invisible
   under a figure. It is drawn in CSS on the body, not shipped as an asset —
   the site holds no image file of any kind. */
--trame:rgba(22,33,28,.055);
--pas:13px;
/* Sections butt against each other and are divided by an ink rule, so the
   between-block gutter is zero by construction. The value survives for the
   column grid, which still needs one. */
--gouttiere:0px;
--marge:26px;
--marge-tel:16px;
}
*{box-sizing:border-box}
html{-webkit-text-size-adjust:100%;scroll-behavior:smooth}
/* Skip link. Fixed, not the classic absolute + left:-9999px — an absolutely
   positioned box with no positioned ancestor is measured against the initial
   containing block, and that has already stretched a document on a sibling
   site. A fixed box takes no part in flow or in scroll size at all. */
[data-evitement]{position:fixed;z-index:20;top:0;left:0;transform:translateY(-200%);background:var(--encre);color:var(--carte);font-family:var(--font-heading);font-size:1rem;letter-spacing:.06em;text-transform:uppercase;padding:10px 16px;text-decoration:none}
[data-evitement]:focus{transform:none;outline:2px solid var(--carte);outline-offset:-4px}
body{margin:0;background-color:var(--bg);background-image:linear-gradient(to right,var(--trame) 1px,transparent 1px),linear-gradient(to bottom,var(--trame) 1px,transparent 1px);background-size:var(--pas) var(--pas);color:var(--text);font-family:var(--font-body);font-size:16px;line-height:1.5;font-variant-numeric:tabular-nums;-webkit-font-smoothing:antialiased}
a{color:var(--primary);text-decoration:none}
a:hover{text-decoration:underline}
/* A link inside prose may not be told apart by colour alone: the slate green
   against the body ink is under the 3:1 that WCAG asks of a colour-only
   distinction. Underlined in running text, bare everywhere the link IS the
   element (nav, rows, chips, map shapes). */
[data-hero] p a,[data-flux] p a,[data-flux] li a,[data-cote] p a,[data-bloc] p a,[data-bloc] li a,[data-faq-immo] p a,[data-sources] p a,[data-energie-loi] a{text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:2px}
:focus-visible{outline:2px solid var(--primary);outline-offset:2px}
h1,h2,h3{font-family:var(--font-heading);color:var(--titre);letter-spacing:.005em}
table{width:100%;border-collapse:collapse;font-family:var(--font-heading);font-size:1.05rem;letter-spacing:.02em}
th{text-align:left;font-weight:600}
/* A column head is a NAME, set small and tracked, over an ink rule — the same
   rule that closes a section, because a table head opens one. */
thead th{padding:4px 8px 5px;border-bottom:1px solid var(--encre);font-size:.8rem;font-weight:600;letter-spacing:.14em;text-transform:uppercase;color:var(--ink-3)}
tbody th,tbody td{padding:6px 8px;border-bottom:1px dashed var(--ligne)}
tbody tr:last-child th,tbody tr:last-child td{border-bottom:0}
thead th:first-child,tbody th:first-child,tbody td:first-child{padding-left:0}
thead th:last-child,tbody td:last-child{padding-right:0}
thead th:not(:first-child),tbody td:not(:first-child){text-align:right}

/* ── shell ─────────────────────────────────────────────────────────────── */
/* The bar is the sheet's own top edge: full-bleed, no slab of its own, closed
   by the same ink rule that divides every section below it. */
.bade4be{background:transparent;border-bottom:1px solid var(--encre);display:flex;align-items:baseline;gap:26px;padding:20px max(var(--marge),calc((100vw - 1280px) / 2)) 16px}
/* The wordmark IS the mark. The previous world owned a 5x28 rule before it;
   this one is a survey sheet, where the sheet is titled in tracked condensed
   capitals and carries nothing else. */
/* WCAG 2.2 SC 2.5.8 asks 24x24 CSS px of a target that is not inline in a
   sentence. The wordmark measured 123x20 and the breadcrumb links 47x19; both
   are navigation, not prose, so the exception does not cover them. Padding is
   all it takes. */
.aae5c0f{display:inline-block;padding:2px 0;font-family:var(--font-heading);font-weight:700;font-size:1.5rem;line-height:1.2;letter-spacing:.06em;text-transform:uppercase;color:var(--titre);white-space:nowrap}
.aae5c0f:hover{text-decoration:none}
.te98377{margin-left:auto}
.te98377 ul{display:flex;align-items:baseline;gap:22px;margin:0;padding:0;list-style:none;font-family:var(--font-heading);font-size:.92rem;font-weight:600;letter-spacing:.12em;text-transform:uppercase}
/* MEASURED at 17 px tall, inline, no padding — under the 24 px floor of WCAG
   2.5.8. The inline-link exemption does not cover these: they are a menu, not
   words inside a sentence. The padding grows the TARGET and the negative margin
   gives back the space, so the hit area reaches 27 px while the header looks
   exactly as it did. */
.te98377 a{color:var(--ink-3);display:inline-block;padding:5px 0;margin:-5px 0}
.te98377 a:hover{color:var(--titre)}
.te98377 li:last-child a{color:var(--titre)}
.k39191f{max-width:1280px;margin:0 auto;padding:0}
/* The dark close. The page has spent its length on the printed ground; the
   footer is where the plate ends, and the reversal is what makes it read as an
   ending rather than as one more section. */
footer{margin-top:0;background:var(--encre);border-top:0}
.i431c3f{max-width:1280px;margin:0 auto;padding:34px var(--marge) 30px;color:#ccd6cf;font-size:.92rem;line-height:1.6}
[data-foot-grid]{display:grid;grid-template-columns:1.7fr 1fr 1fr 1fr;gap:26px}
[data-foot-brand]{margin:0 0 8px;font-family:var(--font-heading);font-weight:700;font-size:1.15rem;letter-spacing:.06em;text-transform:uppercase;color:#f3f5f2}
[data-foot-mission]{margin:0;font-size:.92rem;line-height:1.6;color:#a9b8ae;max-width:40ch}
[data-foot-ops]{display:none}
[data-foot-lab]{margin:0 0 9px;font-family:var(--font-heading);font-size:.8rem;font-weight:700;letter-spacing:.16em;text-transform:uppercase;color:#8fa89a}
[data-foot-nav] a{display:block;padding:.16rem 0;font-size:.92rem;color:#ccd6cf}
[data-foot-nav] a:hover{color:#f3f5f2}
[data-footer-legal] p a{color:#ccd6cf;text-decoration:underline;text-underline-offset:2px}
[data-foot-donnees],[data-footer-legal] p:last-child{margin:26px 0 0;padding-top:14px;border-top:1px solid #2f3d36;font-size:.86rem;line-height:1.6;color:#8fa89a}
[data-foot-donnees]~p{margin-top:.4rem;padding-top:0;border-top:0}

/* ── fil d'ariane ──────────────────────────────────────────────────────── */
/* On a plan, the sheet says where it sits before it says anything else. */
[data-fil]{display:flex;gap:7px;flex-wrap:wrap;font-family:var(--font-heading);font-size:.8rem;font-weight:600;letter-spacing:.16em;text-transform:uppercase;color:var(--ink-3);margin:0;padding:12px var(--marge) 0}
[data-fil] a{display:inline-block;padding:3px 0;color:var(--ink-3)}
[data-fil] [aria-current]{display:inline-block;padding:3px 0;color:var(--titre)}

/* ── plaque ────────────────────────────────────────────────────────────── */
/* No cards. A section is a band of the sheet, closed by an ink rule; that rule
   is the entire container vocabulary this world has. */
[data-hero],[data-flux]>section,[data-tableau],[data-bloc]{background:none;border:0;border-bottom:1px solid var(--encre);border-radius:0;box-shadow:none;padding:18px var(--marge) 20px;margin:0}
[data-hero]{padding-top:14px;padding-bottom:22px}
[data-flux]>section{scroll-margin-top:64px}
[data-hero] h1{margin:0;font-weight:700;font-size:clamp(2.4rem,8.6vw,3.6rem);line-height:.94;text-transform:uppercase;text-wrap:balance}
[data-hero-tete],[data-hero-tete]>div{display:flex;flex-direction:column;gap:8px}
[data-verdict]{margin:0;font-size:1rem;line-height:1.5;color:var(--ink-2);max-width:74ch}
[data-verdict] strong{color:var(--text);font-weight:600}
/* The rank, and the posture. The hero's left column runs 167 px against 399 on
   the right, which left 232 px of printed ground under the intro on a wide
   screen. Two real readings fill it rather than a decoration: WHERE the commune
   sits among the ones we publish, and what this page refuses to be — the
   sentence the comp carries and this build had dropped. */
[data-hero-rang]{margin:0;font-size:1rem;line-height:1.5;color:var(--ink-2);max-width:52ch}
[data-hero-rang] strong{color:var(--titre);font-weight:600}
[data-hero-pied]{display:flex;flex-direction:column;gap:12px;margin-top:16px}
[data-hero-posture]{margin:0;padding-top:12px;border-top:1px dashed var(--ligne);font-size:.95rem;line-height:1.5;color:var(--ink-3);max-width:56ch}
/* The sheet reference. It replaces the old vintage pill: a plan does not badge
   its own date, it prints it in the margin with the sheet number. */
[data-millesime]{margin:0;font-family:var(--font-heading);font-size:.88rem;font-weight:400;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-3)}

/* ── les chiffres ──────────────────────────────────────────────────────── */
/* The signature of this world: the figure at full size on the left, and its
   sample COTED in the margin on the right behind a hairline, the way a
   dimension is called out on a drawing.
   TWO traps, both measured on the built page. The label sits TIGHT above its
   figure — a single shorthand gap set the ROW gap as well as the column one and
   opened 12 px where the comp has 2. And the cote spans with span 3, not
   1 / -1: in a grid with no explicit rows, -1 resolves to line 1, so the cote
   sat in row 1 ALONE and inflated it to the height of its three readings,
   pushing the figure 63 px down the block. */
[data-chiffres]{display:flex;flex-direction:column;gap:16px;margin-top:18px}
/* The cote column is CAPPED, not fixed and not auto. Fixed at 132 px it could
   not hold its own content once WCAG 1.4.12's forced letter-spacing applied;
   auto let it grow to max-content and starve the figure beside it, which then
   overlapped it. A cap that may shrink to zero lets the cote wrap inside itself
   and leaves the figure the rest — and the cap is a PROPORTION, because a 150 px
   one still starved the figure at a 320 px viewport. */
[data-stat]{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,42%);column-gap:12px;row-gap:2px;align-items:start}
[data-stat-lab]{grid-column:1;font-family:var(--font-heading);font-size:.95rem;font-weight:600;letter-spacing:.1em;text-transform:uppercase;color:var(--titre)}
/* Deliberately NOT white-space:nowrap. The figure itself cannot break — its
   thousands separator is a narrow NO-BREAK space — so the only break point is
   before the unit span, and forbidding even that made the figure overlap its
   own cote column under the forced text spacing WCAG 1.4.12 requires. Reflowing
   the unit beats overlapping the neighbour. */
[data-stat-val]{grid-column:1;font-family:var(--font-heading);font-weight:700;font-size:clamp(2rem,10vw,2.7rem);line-height:1;color:var(--primary)}
[data-stat-unite]{font-size:.44em;font-weight:600;margin-left:.12em}
[data-stat-val][data-sens="hausse"]{color:var(--hausse)}
[data-stat-val][data-sens="baisse"]{color:var(--baisse)}
[data-stat-sub]{grid-column:2;grid-row:1 / span 3;border-left:1px solid var(--ligne);padding-left:10px;font-family:var(--font-heading);font-size:1rem;letter-spacing:.02em;color:var(--ink-2);display:flex;flex-direction:column;gap:1px}
[data-cote-item]{display:flex;flex-wrap:wrap;justify-content:space-between;gap:0 6px;min-width:0}
[data-cote-item] span{color:var(--ink-3)}
[data-cote-item] b{font-weight:600;white-space:nowrap}
[data-cote-libre]{display:block;color:var(--ink-3);margin-top:2px}
/* The direction, under the figure it qualifies rather than in the margin
   beside it. Plain ink on purpose: it is the carrier the hue cannot be, and
   tinting it would make it one more thing a dichromat reads as the same grey. */
[data-sens-mot]{grid-column:1;margin-top:3px;font-family:var(--font-heading);font-size:.95rem;font-weight:700;letter-spacing:.12em;text-transform:uppercase;color:var(--titre)}
[data-stat-nd]{grid-column:1;font-size:.9rem;color:var(--ink-3)}
[data-stat][data-vide]{grid-template-columns:1fr}
/* Every cote aligns to the TOP of its block, beside the label, whether the
   block is a median (two rows) or a delta (three). Bottom-aligned, the delta
   cotes sat next to the direction word instead of next to the figure, and the
   four blocks no longer read as one column of readings. */
[data-stat-sub]{align-self:start}

/* ── sous-navigation ───────────────────────────────────────────────────── */
[data-subnav]{position:sticky;top:0;z-index:5;background:var(--bg);border-bottom:1px solid var(--encre);display:flex;gap:0;padding:0 var(--marge);font-family:var(--font-heading);font-size:.85rem;font-weight:600;letter-spacing:.1em;text-transform:uppercase;overflow-x:auto;scrollbar-width:none}
[data-subnav]::-webkit-scrollbar{display:none}
[data-subnav] a{padding:9px 14px 8px;color:var(--ink-3);white-space:nowrap;border-right:1px dashed var(--ligne)}
[data-subnav] a:first-child{padding-left:0}
[data-subnav] a:last-child{border-right:0}
[data-subnav] a:hover{color:var(--primary);text-decoration:none}
/* The band being read. Marked by weight and by an ink underline, not by colour
   alone — and the attribute is what a screen reader announces, so the state is
   not a paint job. */
[data-subnav] a[aria-current]{color:var(--titre);font-weight:700;box-shadow:inset 0 -3px 0 var(--primary)}

/* ── colonnes ──────────────────────────────────────────────────────────── */
[data-cols]{display:grid;grid-template-columns:minmax(0,1fr);align-items:start}
[data-flux]{display:flex;flex-direction:column;gap:var(--gouttiere);min-width:0}
/* The margin of the plate. Not a stack of little cards — one column of readings
   separated by dashed rules, held behind the same ink rule that divides the
   sheet vertically. */
[data-cote]{display:flex;flex-direction:column}
[data-cote]>div{padding:16px var(--marge);border-bottom:1px dashed var(--ligne)}
[data-cote]>div:last-child{border-bottom:0}
[data-cote-lab]{margin:0 0 8px;font-family:var(--font-heading);font-size:.8rem;font-weight:700;letter-spacing:.16em;text-transform:uppercase;color:var(--primary)}
[data-repere]{display:flex;justify-content:space-between;gap:12px;padding:4px 0;border-bottom:1px dashed var(--ligne);font-family:var(--font-heading);font-size:1rem;letter-spacing:.02em}
[data-repere]:last-child{border-bottom:0}
[data-repere] span{color:var(--ink-2)}
[data-repere] strong{font-weight:600;white-space:nowrap}
[data-note-titre]{margin:0 0 4px;font-family:var(--font-heading);font-size:1.05rem;font-weight:600;letter-spacing:.02em;color:var(--titre)}
[data-note-corps]{margin:0;font-size:.92rem;line-height:1.5;color:var(--ink-2)}
/* The one panel that is allowed a fill, because it is the one aside that must
   not read as a reading. */
[data-bloc-sobre]{background:var(--carte)}

/* ── sections ──────────────────────────────────────────────────────────── */
/* A section head is a NAME in tracked capitals, not a headline: the sheet
   labels its bands, it does not title them. */
[data-flux] h2,[data-tableau] h2{margin:0 0 10px;font-family:var(--font-heading);font-size:.82rem;font-weight:700;letter-spacing:.16em;text-transform:uppercase;color:var(--primary);line-height:1.3}
/* The numbering comes from the document, not from the markup: a commune page
   renders a variable set of sections, so a hand-written number would eventually
   disagree with what is actually on the page. */
[data-flux][data-numerote]{counter-reset:bande}
[data-flux][data-numerote]>section{counter-increment:bande}
[data-flux][data-numerote]>section>h2::before{content:counter(bande) " — "}
[data-flux] h3{margin:14px 0 2px;font-family:var(--font-heading);font-size:1.05rem;font-weight:600;letter-spacing:.02em}
[data-flux] h3:first-of-type{margin-top:4px}
[data-typo-lede],[data-cmp-lede],[data-serie-lab]{margin:0 0 8px;font-size:1rem;line-height:1.5;color:var(--ink-2);max-width:72ch}
[data-serie-lab]+[data-serie-lab]{margin-top:-4px}
[data-typo-note],[data-evolution-note],[data-cmp-note],[data-tab-note]{margin:10px 0 0;font-size:.88rem;line-height:1.45;color:var(--ink-3)}
[data-typo-surf]{font-weight:400;color:var(--ink-3);font-size:.88em;margin-left:.3em}
[data-typo-val],[data-annee-val],[data-cmp-val]{font-weight:600}
[data-typo-prix],[data-typo-n],[data-annee-n]{color:var(--ink-3)}
[data-annee-val][data-second]{color:var(--ink-3);font-weight:400}
[data-nd]{color:var(--ink-3)}
td[data-typo-bar]{width:22%}
[data-typo-bar] span{display:block;height:8px;background:var(--ligne-2)}
[data-typo-bar] i{display:block;height:8px;width:var(--w);background:var(--primary)}
[data-quartiers] table{table-layout:fixed}
/* WCAG 1.4.10 admet un défilement en deux dimensions pour ce qui EXIGE une mise
   en page bidimensionnelle — un tableau de données en fait partie. Ce qu'il
   n'admet pas, c'est que la page entière défile : à 320 px ces deux tableaux
   poussaient tout le document. Ils défilent maintenant dans leur propre bande. */
/* The scroll lives on the BAND, not the section: it used to sit on the section,
   so dragging the table dragged its heading and lede off the page with it. */
[data-bande]{overflow-x:auto}
[data-bande]:focus-visible{outline:2px solid var(--primary);outline-offset:2px}
/* An author display:block beats the browser's own [hidden]{display:none}, which
   has already left a hidden control visible on this site. Say it outright. */
[data-bande-note]{margin:6px 0 0;font-size:.88rem;line-height:1.45;color:var(--ink-3)}
[data-bande-note][hidden]{display:none}
[data-q-nom]{font-weight:600}
[data-q-val]{font-weight:600}
[data-q-maison],[data-q-n]{color:var(--ink-3)}
[data-q-ecart][data-sens="hausse"]{color:var(--hausse);font-weight:600}
[data-q-ecart][data-sens="baisse"]{color:var(--baisse);font-weight:600}
[data-q-lede]{margin:0 0 8px;font-size:1rem;line-height:1.5;color:var(--ink-2);max-width:72ch}
[data-q-note]{margin:10px 0 0;font-size:.88rem;line-height:1.45;color:var(--ink-3)}
[data-cmp-txt][data-sens="hausse"]{color:var(--hausse)}
[data-cmp-txt][data-sens="baisse"]{color:var(--baisse)}

/* ── grille de repères (pouvoir d'achat, parc et construction) ─────────── */
[data-kpi-lede]{margin:0 0 12px;font-size:1rem;line-height:1.5;color:var(--ink-2);max-width:72ch}
/* Hairline columns, never a bordered grid: the cells are divided by the rule
   between them and by nothing else. */
[data-kpi-grille]{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));background:none;border:0}
[data-kpi-grille][data-n="1"]{grid-template-columns:1fr}
[data-kpi-grille][data-n="2"]{grid-template-columns:repeat(2,minmax(0,1fr))}
[data-kpi-grille][data-n="4"]{grid-template-columns:repeat(4,minmax(0,1fr))}
[data-kpi-cell]{background:none;padding:0 10px;display:flex;flex-direction:column;gap:2px;border-left:1px solid var(--ligne)}
[data-kpi-cell]:first-child{padding-left:0;border-left:0}
[data-kpi-lab]{font-family:var(--font-heading);font-size:.8rem;font-weight:600;letter-spacing:.08em;text-transform:uppercase;color:var(--ink-3);line-height:1.2;order:2}
[data-kpi-cell] strong{font-family:var(--font-heading);font-size:1.35rem;font-weight:700;color:var(--titre);line-height:1;white-space:nowrap;order:1}
[data-kpi-sub]{font-size:.88rem;color:var(--ink-3);line-height:1.4;order:3}
[data-kpi-note]{margin:10px 0 0;font-size:.88rem;line-height:1.45;color:var(--ink-3)}
@media(max-width:640px){[data-kpi-grille],[data-kpi-grille][data-n="4"]{grid-template-columns:repeat(2,minmax(0,1fr));gap:12px 0}}

/* ── calcul ────────────────────────────────────────────────────────────── */
[data-calc-champs]{display:flex;flex-wrap:wrap;gap:12px;margin:12px 0 0}
[data-calc-lab]{display:flex;flex-direction:column;gap:4px;font-family:var(--font-heading);font-size:.8rem;font-weight:600;letter-spacing:.08em;text-transform:uppercase;color:var(--ink-3)}
[data-calc-champs] select,[data-calc-champs] input{font-family:var(--font-heading);font-size:1.05rem;letter-spacing:.02em;padding:.42rem .6rem;border:1px solid var(--encre);border-radius:0;background:var(--carte);color:var(--text)}
[data-calc-champs] select{min-width:15rem}
[data-calc-surface-champ]{display:inline-flex;align-items:center;gap:7px;color:var(--ink-3);font-size:.85rem;text-transform:none;letter-spacing:0;font-weight:400;font-family:var(--font-body)}
[data-calc-surface]{width:6rem;text-align:right}
[data-calc-sortie]{display:flex;flex-wrap:wrap;align-items:baseline;gap:10px;margin:14px 0 0;font-size:.92rem;color:var(--ink-2)}
[data-calc-total]{font-family:var(--font-heading);font-size:2rem;font-weight:700;color:var(--primary);line-height:1}
[data-calc-base]{margin:6px 0 0;font-size:.88rem;color:var(--ink-3)}

/* ── énergie ───────────────────────────────────────────────────────────── */
[data-energie-lede]{margin:0 0 12px;font-size:1rem;line-height:1.5;color:var(--ink-2);max-width:72ch}
[data-dpe-barre]{display:flex;height:10px;margin:0 0 12px}
[data-dpe-barre] span{width:var(--w);display:block}
[data-dpe-barre] i{display:none}
/* The A-G ramp is the one printed on every French DPE, so a reader already
   owns it. It is the single green-to-red scale this site is allowed, and it is
   borrowed rather than invented — MEASURED: ink on A-E clears 5,4:1 and white
   on F-G clears 4,7:1. */
[data-etq="A"]{background:#3aa93a}
[data-etq="B"]{background:#5aa832}
[data-etq="C"]{background:#8a9c26}
[data-etq="D"]{background:#c9a521}
[data-etq="E"]{background:#d1841f}
[data-etq="F"]{background:#bb4e1a}
[data-etq="G"]{background:#a82f1c}
/* Seven readings, one per class: letter, extent, share, count — the same row
   the rest of the sheet uses, so the ramp does not become a separate object. */
[data-dpe-legende]{list-style:none;display:flex;flex-direction:column;gap:3px;margin:0;padding:0;font-family:var(--font-heading);font-size:1rem;letter-spacing:.02em}
[data-dpe-item]{display:grid;grid-template-columns:18px minmax(0,1fr) minmax(0,auto) minmax(0,auto);gap:8px;align-items:center;padding:0;border:0;white-space:nowrap}
[data-dpe-item] b{font-weight:700;color:var(--encre);text-align:center;font-size:.92rem;line-height:1.5}
[data-dpe-item]::after{content:"";grid-column:2;grid-row:1;height:10px;background:rgba(22,33,28,.07);width:100%}
[data-dpe-item] i{grid-column:2;grid-row:1;display:block;height:10px;width:var(--w);z-index:1;font-style:normal}
[data-dpe-item][data-lettre="A"] b,[data-dpe-item][data-lettre="A"] i{background:#3aa93a}
[data-dpe-item][data-lettre="B"] b,[data-dpe-item][data-lettre="B"] i{background:#5aa832}
[data-dpe-item][data-lettre="C"] b,[data-dpe-item][data-lettre="C"] i{background:#8a9c26}
[data-dpe-item][data-lettre="D"] b,[data-dpe-item][data-lettre="D"] i{background:#c9a521}
[data-dpe-item][data-lettre="E"] b,[data-dpe-item][data-lettre="E"] i{background:#d1841f}
[data-dpe-item][data-lettre="F"] b,[data-dpe-item][data-lettre="F"] i{background:#bb4e1a}
[data-dpe-item][data-lettre="G"] b,[data-dpe-item][data-lettre="G"] i{background:#a82f1c}
[data-dpe-item][data-lettre="F"] b,[data-dpe-item][data-lettre="G"] b{color:#fff}
[data-dpe-part]{font-weight:600;text-align:right;min-width:3.2em}
[data-dpe-n]{color:var(--ink-3);text-align:right;min-width:3.6em}

/* The folded quartier tail. Only 29 pages of 356 ever render it. */
[data-q-suite] summary{cursor:pointer;list-style:none;display:flex;align-items:center;gap:8px;padding:10px 0 4px;font-family:var(--font-heading);font-size:.95rem;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--primary)}
[data-q-suite] summary::-webkit-details-marker{display:none}
[data-q-suite][open] [data-chev]{transform:rotate(180deg)}
/* An aside is a filled panel with a hairline all round. It shipped for a month
   as a 3 px coloured left border, which the craft floor names as the single
   most recognizable tell of a generated interface. */
[data-energie-loi]{margin:12px 0 0;padding:12px 14px;background:var(--carte);border:1px solid var(--ligne);border-radius:0;font-size:.95rem;line-height:1.55;color:var(--ink-2)}
[data-energie-note]{margin:10px 0 0;font-size:.88rem;line-height:1.45;color:var(--ink-3)}

/* ── infobulles de survol ──────────────────────────────────────────────── */
/* Pure CSS, no script. Both hosts are aria-hidden decoration whose numbers are
   already published in full underneath, so the hover is an enhancement and
   nothing is lost without a pointer. Nothing here is focusable: focusable
   content inside aria-hidden would strand a keyboard user on something a
   screen reader cannot announce. */
[data-info]{position:relative}
[data-info]:hover{z-index:6}
[data-info]:hover::after{content:attr(data-info);position:absolute;bottom:calc(100% + 8px);left:50%;transform:translateX(-50%);background:var(--encre);color:#f3f5f2;font-family:var(--font-heading);font-size:.9rem;font-weight:600;letter-spacing:.03em;line-height:1.3;padding:4px 8px;border-radius:0;white-space:nowrap;pointer-events:none;text-transform:none}

/* ── risques ───────────────────────────────────────────────────────────── */
[data-risque-lede]{margin:0 0 6px;font-size:1rem;line-height:1.5;color:var(--ink-2);max-width:72ch}
[data-risque-groupe]{margin:12px 0 0}
[data-risque-groupe] ul{list-style:none;margin:6px 0 0;padding:0;display:flex;flex-wrap:wrap;gap:5px}
/* Intensity is carried by FILL, not by an outline colour: an outlined chip is
   the weakest reading, a mid fill the middle one, full ink the strongest. */
[data-risque]{display:inline-flex;align-items:center;gap:6px;padding:2px 8px;border:1px solid var(--ink-3);border-radius:0;font-family:var(--font-heading);font-size:.92rem;letter-spacing:.04em;text-transform:uppercase;color:var(--ink-2);background:none}
[data-risque][data-fam="techno"]{border-style:dashed}
[data-risque-int]{font-weight:700;color:inherit;text-transform:none}
[data-risque][data-niveau="modéré"]{background:var(--ink-3);border-color:var(--ink-3);color:var(--bg)}
/* A commune carries nine of these in the median, so a chip that says
   "important" has to look different from the eight around it — otherwise the
   one line that distinguishes this commune reads like the rest. */
[data-risque][data-niveau="important"]{background:var(--encre);border-color:var(--encre);color:var(--bg)}
[data-risque-note]{margin:10px 0 0;font-size:.88rem;line-height:1.45;color:var(--ink-3)}

/* ── graphe ────────────────────────────────────────────────────────────── */
[data-graph]{margin:12px 0 4px}
[data-graph-legende]{display:flex;gap:18px;margin:0 0 10px;font-family:var(--font-heading);font-size:.85rem;letter-spacing:.06em;text-transform:uppercase;color:var(--ink-3)}
[data-graph-cle]{display:flex;align-items:center;gap:7px}
/* MEASURED: the two series are #2c5f4f and #4a5a52, which sit 1,01:1 apart —
   they differ by HUE alone, and simulated protanopia and deuteranopia leave
   them at 1,02. Colour cannot be the distinction, so the shape is: the flats
   run solid with round markers, the houses dashed with square ones, and the
   legend swatch carries the same dash. */
[data-graph-cle]::before{content:"";width:16px;height:2px;background:repeating-linear-gradient(to right,var(--ink-3) 0 5px,transparent 5px 9px)}
[data-graph-unite]{margin-left:auto}
[data-graph-cle][data-kind="appartement"]::before{background:var(--primary)}
[data-graph-plot]{position:relative;height:200px;padding-left:48px}
[data-graph-plot] svg{width:100%;height:100%;overflow:visible}
[data-grid]{stroke:var(--ligne);stroke-width:1;stroke-dasharray:2 4}
[data-line]{fill:none;stroke:var(--ink-3);stroke-width:2;vector-effect:non-scaling-stroke;stroke-dasharray:5 4}
[data-line][data-kind="appartement"]{stroke:var(--primary);stroke-dasharray:none}
/* Markers are HTML, not SVG circles: the plot is stretched to fill its column,
   so a circle inside it renders as an ellipse (measured 2,0 x 4,3 px at 390 px
   wide). A span sized in px cannot be stretched by the viewBox. */
/* One hit area per YEAR, spanning the plot's full height. It replaces a tooltip
   on each 7 px dot: the dot gave a 21 px target the reader had to find first,
   answered for one series at a time, and said nothing at all on the flat part of
   a line. A band is the width of a year, so the target is 60 to 170 px wide and
   the readout can answer the real question — what did this year cost, for both
   types, on how many sales. */
[data-graph-bandes]{position:absolute;inset:0 0 0 48px}
[data-graph-bande]{position:absolute;top:0;bottom:0;left:var(--x);width:var(--w);transform:translateX(-50%)}
/* The markers live INSIDE their band, which is what lets one hover thicken a
   whole column: the band spans the full height, so --y stays a plain
   percentage of the plot. */
[data-graph-pt]{position:absolute;pointer-events:none;left:var(--p);top:var(--y);width:7px;height:7px;margin:-3.5px 0 0 -3.5px;border-radius:0;background:var(--ink-3);transition:transform .12s ease}
[data-graph-pt][data-kind="appartement"]{background:var(--primary);border-radius:50%}
/* scale(), not width/height/margin: those three trigger layout on every frame.
   The marker's negative margins already centre it on its data point, so it
   scales about the point itself. */
[data-graph-bande]:hover [data-graph-pt]{transform:scale(1.6)}
/* A plumb line, the way a reading is called out on a plan. */
[data-graph-guide]{position:absolute;top:0;bottom:0;left:var(--p);width:1px;margin-left:-.5px;background:var(--encre);opacity:0;transition:opacity .12s ease}
[data-graph-bande]:hover [data-graph-guide]{opacity:.32}
/* Inside the plot, not above it: anchored over the figure the bubble covered
   the trend sentence, and a readout that hides the prose it explains is a bad
   trade. Width is capped and the lines wrap, because at 390 px a nowrap bubble
   on a middle column ran past the band. */
[data-graph-bulle]{display:none;position:absolute;top:2px;left:50%;transform:translateX(-50%);z-index:6;background:var(--encre);color:#f3f5f2;padding:6px 9px;font-family:var(--font-heading);font-size:.92rem;letter-spacing:.02em;line-height:1.35;width:max-content;max-width:min(230px,62vw);pointer-events:none}
[data-graph-bande]:hover [data-graph-bulle]{display:block}
/* The edge bands run to the edge of the plot instead of overhanging it. A
   centred band on the last year spilled 31 px past the plate and gave the
   whole page a horizontal scrollbar at 390 px; widening them also hands the
   plot's own margins to the year they belong to. */
[data-graph-bande][data-bord="debut"]{left:0;transform:none;width:calc(var(--x) + var(--w) / 2)}
[data-graph-bande][data-bord="fin"]{left:auto;right:0;transform:none;width:calc(100% - var(--x) + var(--w) / 2)}
[data-graph-bande][data-bord="debut"] [data-graph-bulle]{left:0;transform:none}
[data-graph-bande][data-bord="fin"] [data-graph-bulle]{left:auto;right:0;transform:none}
[data-bulle-an]{display:block;font-weight:700;letter-spacing:.14em;color:#8fa89a}
[data-bulle-ligne]{display:flex;justify-content:space-between;gap:14px}
[data-bulle-ligne] b{font-weight:700}
/* The line's own series colour, on ink — the same two voices as the plot, at a
   luminance that works on a dark ground. */
[data-bulle-ligne][data-kind="appartement"] b{color:#7fc0a8}
[data-bulle-ligne][data-kind="maison"] b{color:#e0e6e0}
[data-bulle-n]{display:block;margin-top:2px;color:#a9b8ae}
[data-graph-y]{position:absolute;left:0;width:44px;text-align:right;top:var(--t);transform:translateY(-50%);font-family:var(--font-heading);font-size:.88rem;color:var(--ink-3)}
[data-graph-x]{display:flex;justify-content:space-between;margin:6px 0 0 48px;font-family:var(--font-heading);font-size:.85rem;color:var(--ink-3)}

/* ── FAQ ───────────────────────────────────────────────────────────────── */
[data-faq-immo] details{border-top:1px dashed var(--ligne);padding:10px 0}
[data-faq-immo] details:first-of-type{border-top:0}
[data-faq-immo] summary{cursor:pointer;list-style:none;display:flex;justify-content:space-between;gap:20px;font-family:var(--font-heading);font-size:1.1rem;font-weight:600;letter-spacing:.02em;color:var(--text)}
[data-faq-immo] summary::-webkit-details-marker{display:none}
[data-chev]{color:var(--ink-3);transition:transform .2s ease;flex:none}
[data-chev]::before{content:"\25be"}
[data-faq-immo] details[open] [data-chev]{transform:rotate(180deg)}
[data-faq-immo] p{margin:6px 0 0;font-size:1rem;line-height:1.55;color:var(--ink-2);max-width:72ch}
/* L'analyse ecrite a la main. Elle ouvre le flux, donc elle porte la mesure de
   lecture la plus large du site : c'est le seul bloc de prose suivie de la page,
   tout le reste etant du tableau commente. */
[data-analyse] p{margin:0 0 10px;font-size:1.02rem;line-height:1.6;color:var(--ink-2);max-width:70ch}
[data-analyse] p:last-child{margin-bottom:0}

[data-sources] h2{color:var(--primary)}
[data-sources] p{margin:0;font-size:.95rem;line-height:1.6;color:var(--ink-2);max-width:74ch}

/* ── annuaires (departement + accueil) ─────────────────────────────────── */
/* Fixed widths, not auto: every row is its own grid, so an auto column would
   size to its own content and the price column would zig-zag down the page. */
[data-entete],[data-ligne]{display:grid;grid-template-columns:minmax(0,1fr) 7rem 5rem 6rem;gap:12px;align-items:baseline;font-family:var(--font-heading);letter-spacing:.02em}
[data-entete]{font-size:.8rem;letter-spacing:.14em;text-transform:uppercase;color:var(--ink-3);font-weight:600;border-bottom:1px solid var(--encre);padding-bottom:5px}
[data-entete] span:not(:first-child),[data-ligne] [data-c-m2],[data-ligne] [data-c-n]{text-align:right}
[data-ligne]{padding:5px 0;border-bottom:1px dashed var(--ligne);color:inherit;font-size:1.05rem}
a[data-ligne]:hover{text-decoration:none}
a[data-ligne]:hover [data-c-nom]{color:var(--primary);text-decoration:underline}
/* Wrapping, never truncating: a clipped commune name is a data loss, and
   "Saint-Rémy-de-Provence…" is a worse row than a two-line one. */
[data-c-nom]{min-width:0}
[data-c-m2]{font-weight:600;white-space:nowrap}
[data-c-n]{color:var(--ink-3);white-space:nowrap}
[data-c-rdt]{color:var(--ink-3);white-space:nowrap;text-align:right}
[data-entete] span:not(:first-child),[data-ligne] [data-c-m2],[data-ligne] [data-c-n],[data-ligne] [data-c-rdt]{text-align:right}
[data-sans-page] [data-c-nom]{color:var(--ink-3)}
[data-retour]{margin:0;padding:16px var(--marge) 20px;font-family:var(--font-heading);font-size:.95rem;letter-spacing:.06em;text-transform:uppercase}

/* ── accueil ───────────────────────────────────────────────────────────── */
/* The home page has two jobs no other page has: get a visitor to one of 2 180
   commune pages, and say what the file is. The claim is set as the sheet's own
   title — full width, condensed capitals, on the printed ground with no plate
   of its own. */
[data-hero-accueil]{background:none;border:0;box-shadow:none;border-radius:0;padding:22px var(--marge) 26px;border-bottom:1px solid var(--encre)}
[data-hero-accueil] h1{font-size:clamp(2.1rem,7.4vw,3.5rem);line-height:1;margin:0 0 12px;font-weight:700;text-transform:uppercase;text-wrap:balance}
/* The claim's two weights: the first clause carries, the remainder recedes.
   The split comes from the sentence's own comma, never from a character count. */
[data-h1-suite]{font-weight:400;color:var(--ink-3)}
[data-hero-grille]{display:grid;gap:20px}
[data-hero-creed]{margin:0;font-size:1rem;line-height:1.5;color:var(--ink-2);max-width:46ch}
[data-creed-fort]{color:var(--titre);font-weight:600;text-decoration:underline;text-decoration-thickness:2px;text-underline-offset:4px;text-decoration-color:var(--primary)}
[data-hero-methode]{min-width:0;max-width:52ch}
[data-hero-methode] h2{margin:0 0 8px;font-family:var(--font-heading);font-size:.82rem;font-weight:700;letter-spacing:.16em;text-transform:uppercase;color:var(--primary)}
[data-hero-methode] p{margin:0 0 8px;font-size:1rem;line-height:1.55;color:var(--ink-2)}
[data-methode-chute]{color:var(--ink-2);border-top:1px dashed var(--ligne);padding-top:8px}
[data-methode-lien]{margin:10px 0 0 !important;font-family:var(--font-heading);font-size:.95rem;letter-spacing:.08em;text-transform:uppercase}
[data-accueil-paire]{display:grid;gap:0}
[data-bloc-cherche] [data-cherche]{margin-top:10px;max-width:none}
[data-bloc-chiffres] [data-chiffres]{margin-top:10px}
/* What the file holds: a run of readings, label left and figure right, which is
   how the rest of the sheet already states a quantity. */
[data-bloc-chiffres] [data-stat]{grid-template-columns:minmax(0,1fr) auto;align-items:baseline;padding:4px 0;border-bottom:1px dashed var(--ligne);gap:12px}
[data-bloc-chiffres] [data-chiffres]{gap:0}
[data-bloc-chiffres] [data-stat]:last-child{border-bottom:0}
[data-bloc-chiffres] [data-stat-lab]{font-weight:400;letter-spacing:.04em;color:var(--ink-2)}
[data-bloc-chiffres] [data-stat-val]{grid-column:2;grid-row:1;font-size:1.15rem;color:var(--titre);text-align:right}
[data-bloc-chiffres] [data-stat-unite]{font-size:.72em}
[data-bloc-chiffres] [data-stat-sub]{grid-column:1 / -1;grid-row:2;border-left:0;padding-left:0;font-size:.82rem;color:var(--ink-3);display:block}
[data-sec-lede]{margin:0 0 12px;font-size:.95rem;line-height:1.5;color:var(--ink-2);max-width:74ch}

/* The lookup. Label and field ship hidden and the script is what reveals them,
   so a browser with no JavaScript never shows a control that cannot work.
   min-height reserves the MEASURED height of the revealed block, so revealing
   costs no layout shift and the noscript line sits in the same reserved box. */
[data-cherche]{position:relative;margin:12px 0 0;max-width:34rem;min-height:76px}
/* The section head already says "Trouver une commune"; a visible label over the
   field restated it. The label stays for the combobox's accessible name. */
[data-cherche-lab]{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}
/* A <label> is inline, so it needs display:block above — and an author
   display:block BEATS the browser's own [hidden]{display:none}. Without this
   line the label stayed visible with no JavaScript, captioning an empty box. */
[data-cherche-lab][hidden]{display:none}
[data-cherche-champ]{width:100%;padding:.5rem .7rem;border:1px solid var(--encre);border-radius:0;font-family:var(--font-heading);font-size:1.2rem;letter-spacing:.02em;background:var(--carte);color:var(--text)}
[data-cherche-champ]::placeholder{color:var(--ink-3)}
[data-cherche-champ]:focus{border-color:var(--primary)}
[data-cherche-liste]{position:absolute;z-index:8;left:0;right:0;margin-top:0;max-height:22rem;overflow-y:auto;background:var(--carte);border:1px solid var(--encre);border-top:0;border-radius:0;box-shadow:none;font-family:var(--font-heading);font-size:1.05rem;letter-spacing:.02em}
[data-cherche-liste] a{display:grid;grid-template-columns:minmax(0,1fr) 4rem 6.5rem;gap:10px;align-items:baseline;padding:.4rem .7rem;color:inherit;border-top:1px dashed var(--ligne)}
[data-cherche-liste] a:first-child{border-top:0}
[data-cherche-liste] a:hover{background:var(--ligne-2);text-decoration:none}
/* The keyboard-active option must not look merely hovered: the bar is what
   tells a keyboard user which row Enter will follow. */
[data-cherche-liste] a[aria-selected="true"]{background:var(--primary);color:var(--carte)}
[data-cherche-liste] a[aria-selected="true"] b,[data-cherche-liste] a[aria-selected="true"] [data-o-cp]{color:var(--carte)}
[data-cherche-liste] b{font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
[data-o-cp]{color:var(--ink-3)}
[data-o-prix]{text-align:right;font-weight:700;white-space:nowrap}
[data-cherche-etat]{margin:8px 0 0;min-height:1.3em;font-size:.92rem;line-height:1.45;color:var(--ink-3)}
[data-cherche-noscript]{margin:8px 0 0;font-size:.92rem;line-height:1.5;color:var(--ink-2)}

/* A ranked list, not a chip wall: the rank carries the "classées par
   population" caption, and the prices line up so a reader compares down a
   column. The number comes from the <ol>, so the markup cannot disagree with
   what is drawn. */
[data-villes]{list-style:none;margin:0;padding:0;counter-reset:ville}
[data-villes] li{counter-increment:ville}
[data-ville]{display:grid;grid-template-columns:1.4rem minmax(0,1fr) auto;gap:8px;align-items:baseline;padding:3px 0;border-bottom:1px dashed var(--ligne);color:inherit;font-family:var(--font-heading);font-size:1.05rem;letter-spacing:.02em;line-height:1.35}
[data-villes] li:last-child [data-ville]{border-bottom:0}
[data-ville]::before{content:counter(ville);color:var(--ink-3);font-size:.85rem;text-align:right}
[data-ville]:hover{text-decoration:none}
[data-ville]:hover [data-ville-nom]{color:var(--primary);text-decoration:underline}
[data-ville-nom]{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
[data-ville-prix]{font-weight:700;white-space:nowrap;text-align:right}

/* 97 départements as ruled columns rather than 97 pills: the code IS the
   ordering, so it reads as an index instead of a tag cloud. */
[data-depts]{columns:2;column-gap:22px;column-rule:1px solid var(--ligne)}
[data-dept]{display:flex;align-items:baseline;gap:8px;padding:2px 0;color:inherit;font-family:var(--font-heading);font-size:1rem;letter-spacing:.02em;break-inside:avoid}
[data-dept-code]{width:1.7rem;flex:none;color:var(--ink-3);font-size:.88rem}
/* Wrapping, never truncating: at 5 columns "Alpes-de-Haute-Provence" came out
   as "Alpes-de-Haute-Prove…", and a clipped département name is a worse row
   than a two-line one. */
[data-dept-nom]{min-width:0}

/* ── cartogramme ───────────────────────────────────────────────────────── */
/* One square per département on a 13-column plan grid, not the geographic
   outline. At 390 px the true shapes put Paris at 2 px and the Gironde at 40,
   so the map read as a picture of France rather than as 97 comparable
   readings. Squares give every département the same voice; the ordering is
   still geographic, so the reader keeps north, south, the coasts and Corsica. */
/* Capped, and centred in whatever column it lands in. Uncapped in the atlas
   pair the 10x13 grid drew 725 px wide and 942 tall — a plate taller than the
   viewport, where the whole point of squaring the départements was to make the
   comparison fit in one look. */
[data-carte] svg{width:100%;height:auto;max-height:32rem;display:block}
[data-carto] svg{max-width:420px;max-height:none;margin:0 auto}
[data-carte]{position:relative;margin:10px 0 0}
/* Both maps are stroked in the ground colour so the sheet itself separates the
   shapes. The cartogram's squares need a thick gap to read as separate tiles;
   a commune contour needs a hairline — without one the 207 communes of a
   département merge into a single blob of green. */
[data-carte] rect{stroke:var(--bg);stroke-width:1.4}
[data-carte] path{stroke:var(--bg);stroke-width:.4;stroke-linejoin:round}
[data-carte] text{font-family:var(--font-heading);font-size:5.4px;font-weight:600;letter-spacing:.02em;text-anchor:middle;pointer-events:none}
[data-carte] a:focus{outline:none}
[data-carte] a:focus-visible rect,[data-carte] a:focus-visible path,[data-carte] [data-nom]:hover{stroke:var(--encre);stroke-width:1.6;paint-order:stroke}
[data-carte-info]{position:absolute;z-index:2;pointer-events:none;background:var(--encre);color:#f3f5f2;padding:.28rem .5rem;border-radius:0;font-family:var(--font-heading);font-size:.9rem;line-height:1.35;letter-spacing:.02em;white-space:nowrap;box-shadow:none}
[data-carte-info] b{display:block;font-weight:700}
[data-carte-info] span{color:#a9b8ae}
/* Six steps of one hue, mixed to the ground rather than to white so the ladder
   sits ON the sheet. A green-to-red diverging ramp was offered and rejected:
   a price is a quantity, not a verdict. */
[data-vide]{fill:url(#sansdonnee)}
[data-q="0"]{fill:#dfe5df}
[data-q="1"]{fill:#c5d1c8}
[data-q="2"]{fill:#9ab3a3}
[data-q="3"]{fill:#6f9483}
[data-q="4"]{fill:#487564}
[data-q="5"]{fill:#2c5f4f}
[data-q="0"]+text,[data-q="1"]+text,[data-q="2"]+text{fill:var(--encre)}
[data-q="3"]+text,[data-q="4"]+text,[data-q="5"]+text{fill:#f3f5f2}
[data-vide]+text{fill:var(--ink-3)}
/* The legend keeps the CLASS RANGES rather than the comp's bare min-to-max
   ramp: a ramp with two bounds cannot tell you what a given green is worth,
   and on this site a colour that cannot be read back to a figure is exactly
   the thing we do not ship. */
[data-carte-leg]{display:flex;flex-wrap:wrap;gap:.4rem 1rem;align-items:center;margin-top:8px;font-size:.88rem;color:var(--ink-3)}
[data-leg]{display:inline-flex;align-items:center;gap:.4rem}
[data-leg]::before{content:"";width:14px;height:10px;display:block}
[data-leg][data-q="0"]::before{background:#dfe5df}
[data-leg][data-q="1"]::before{background:#c5d1c8}
[data-leg][data-q="2"]::before{background:#9ab3a3}
[data-leg][data-q="3"]::before{background:#6f9483}
[data-leg][data-q="4"]::before{background:#487564}
[data-leg][data-q="5"]::before{background:#2c5f4f}
[data-leg-vide]::before{background:repeating-linear-gradient(45deg,var(--bg) 0 2px,var(--ligne) 2px 4px)}
[data-carte-note]{flex:1 1 100%;line-height:1.45}
[data-carte-bloc]{padding-bottom:18px}

/* ── filtre ────────────────────────────────────────────────────────────── */
[data-filtre]{display:flex;align-items:center;gap:.6rem;flex-wrap:wrap;margin:0 0 12px}
[data-filtre] label{font-family:var(--font-heading);font-size:.8rem;letter-spacing:.14em;text-transform:uppercase;color:var(--ink-3);font-weight:600}
[data-filtre-champ]{flex:1 1 16rem;max-width:22rem;padding:.35rem .6rem;border:1px solid var(--encre);border-radius:0;font-family:var(--font-heading);font-size:1.05rem;background:var(--carte);color:var(--text)}
[data-filtre-champ]:focus{border-color:var(--primary)}
[data-filtre-etat]{font-size:.88rem;color:var(--ink-3)}
[data-flux][data-seul]{margin-top:0}
[data-volume] table{max-width:26rem}

/* ── pages de texte ────────────────────────────────────────────────────── */
[data-bloc] h1{margin:0 0 8px;font-size:clamp(2rem,7vw,2.8rem);line-height:.98;text-transform:uppercase}
[data-bloc] h2{margin:22px 0 6px;font-family:var(--font-heading);font-size:.82rem;font-weight:700;letter-spacing:.16em;text-transform:uppercase;color:var(--primary)}
[data-bloc] p,[data-bloc] li{font-size:1rem;line-height:1.6;color:var(--ink-2);max-width:74ch}
[data-bloc] label{display:block;margin:12px 0 4px;font-family:var(--font-heading);font-weight:600;font-size:.8rem;letter-spacing:.14em;text-transform:uppercase;color:var(--ink-3)}
/* MEASURED on a phone: 36 px for the text fields, 38 for the select, 35 for the
   submit. All clear the 24 px floor of WCAG 2.5.8, none reached the 44 px a
   thumb actually wants. min-height does the work rather than more padding, so
   the ink rule keeps its weight and the field its proportion. */
[data-bloc] input:not([type=checkbox]):not([type=radio]),[data-bloc] textarea,[data-bloc] select{width:100%;max-width:34rem;min-height:44px;padding:.45rem .7rem;border:1px solid var(--encre);border-radius:0;font-family:var(--font-heading);font-size:1.05rem;background:var(--carte);color:var(--text)}
/* The widget renders in the light DOM, so its box is ours to size. The checkbox
   shipped at 22x22, under the floor, and it is the one control the form cannot
   be sent without. */
altcha-widget input[type=checkbox]{width:24px;height:24px}
[data-bloc] select{max-width:24rem}
[data-bloc] input:focus,[data-bloc] textarea:focus,[data-bloc] select:focus{border-color:var(--primary)}
[data-bloc] textarea{min-height:9rem;font-family:var(--font-body);font-size:1rem}
/* The one button on the site. Square, ink-filled, tracked capitals: a stamp on
   the sheet rather than a pill. */
[data-bloc] button{margin-top:14px;min-height:44px;padding:.5rem 1.2rem;border:0;border-radius:0;background:var(--primary);color:#f3f5f2;font-family:var(--font-heading);font-size:1rem;font-weight:700;letter-spacing:.1em;text-transform:uppercase;cursor:pointer}
[data-bloc] button:hover{background:var(--encre)}

/* ── au-dessus du téléphone ────────────────────────────────────────────── */
@media (min-width:981px){
body{font-size:17px}
/* The sheet has edges: two ink-grey rules the full height of the plate, so the
   printed ground reads as a document laid on a surface rather than as a page
   colour. */
.k39191f{border-left:1px solid var(--bord);border-right:1px solid var(--bord)}
[data-cols]{grid-template-columns:minmax(0,1fr) 330px}
[data-cote]{position:sticky;top:52px;border-left:1px solid var(--encre);align-self:start}
[data-flux]>section,[data-hero],[data-tableau],[data-bloc],[data-hero-accueil]{padding-left:var(--marge);padding-right:var(--marge)}
/* The commune hero reads in two: the claim and its sample on the left, the two
   medians called out on the right, divided by the same rule as everything
   else. NOT the home hero, which carries both attributes and has its own pair —
   unscoped, this rule halved the home claim's column and wrapped a 56 px
   headline into six lines. */
[data-hero]:not([data-hero-accueil]){display:grid;grid-template-columns:minmax(0,1.05fr) minmax(0,1fr);gap:0 26px;align-items:start}
/* Explicit placement, because the DOM order is the MOBILE order: the medians
   come before the rank and the posture there, so a phone reads the money figure
   before the commentary. On a wide screen the two commentary blocks drop back
   into the left column under the intro, where they close the 232 px of empty
   ground the short intro used to leave. */
[data-hero]:not([data-hero-accueil]) [data-hero-tete]{grid-column:1;grid-row:1}
[data-hero]:not([data-hero-accueil]) [data-hero-pied]{grid-column:1;grid-row:2;padding-top:14px}
[data-hero]:not([data-hero-accueil]) [data-chiffres]{grid-column:2;grid-row:1 / span 2;margin-top:0;border-left:1px solid var(--ligne);padding-left:26px}
/* Capped in px above the phone: 42 % of a 558 px column is 234 px of cote and
   leaves a canyon between the figure and its own hairline. The comp reads at
   about 30 % of a 390 px sheet, which is what this holds on a wide one. */
[data-stat]{grid-template-columns:minmax(0,1fr) minmax(0,190px)}
[data-hero-tete]{padding-bottom:4px}
[data-stat-val]{font-size:clamp(2.4rem,3vw,3rem)}
/* The home page reads in PAIRS, divided by an ink rule rather than by a gap:
   the claim beside the method, the lookup beside what the file holds, the map
   beside the ranking. */
[data-hero-grille]{grid-template-columns:minmax(0,1.15fr) minmax(0,1fr);gap:0 34px}
[data-hero-methode]{border-left:1px solid var(--ligne);padding-left:34px}
[data-accueil-paire]{grid-template-columns:minmax(0,1fr) minmax(0,1.55fr)}
[data-accueil-paire]>[data-tableau]{border-bottom:0}
[data-accueil-paire]>[data-tableau]+[data-tableau]{border-left:1px solid var(--ligne)}
[data-accueil-paire]{border-bottom:1px solid var(--encre)}
[data-paire-atlas]{grid-template-columns:minmax(0,1.55fr) minmax(0,1fr)}
[data-depts]{columns:4;column-gap:30px}
[data-fil]{padding-top:14px}
}
@media (min-width:1200px){
[data-depts]{columns:5}
}

/* ── téléphone ─────────────────────────────────────────────────────────── */
@media (max-width:980px){
:root{--marge:var(--marge-tel)}
/* The home page's reading order, on a phone only.
 *
 * The pairs collapse to one column here, and collapsing put the 236 px method
 * block between the claim and the lookup: MEASURED, the search field started at
 * 607 px on an iPhone, 643 on a 360-wide Android and 726 on a small screen —
 * below the fold on the last two and flush against the edge on the first, on the
 * one page whose whole purpose is to find a commune.
 *
 * The claim still leads. Only the method steps behind the field.
 *
 * display:contents is what lets two elements in DIFFERENT containers order
 * against each other. It drops the hero's own box, so the band it drew — side
 * margins and closing rule — is re-drawn on the two children that inherit its
 * place. Selectors keep matching on the DOM tree, not the flattened one, which
 * is why the child combinator still reaches only the last section.
 *
 * ⚠️ Known and accepted cost: the DOM keeps the method before the lookup, so a
 * keyboard reaches the method's link before the field that now sits above it.
 * The alternative was re-pairing the blocks, which would have moved the desktop
 * composition the charter records. Above 980 px NOTHING here applies.
 */
[data-accueil]{display:flex;flex-direction:column}
[data-hero-accueil],[data-hero-grille],[data-paire-entree]{display:contents}
[data-hero-texte]{order:1}
[data-bloc-cherche]{order:2}
[data-hero-methode]{order:3}
[data-bloc-chiffres]{order:4}
[data-paire-atlas]{order:5}
[data-accueil]>[data-tableau]{order:6}
[data-hero-texte],[data-hero-methode]{border-bottom:1px solid var(--encre);padding:18px var(--marge) 20px}
[data-hero-texte]{padding-top:22px}
[data-hero-methode]{max-width:none}
.bade4be{padding:14px var(--marge) 12px;gap:12px;flex-wrap:wrap}
.aae5c0f{font-size:1.25rem}
.te98377{width:100%;margin-left:0}
/* MEASURED at 360 px: the three destinations need 345 px and have 328, so the
   third wrapped and the header grew 87 → 124 px. It was 17 px short, not a
   structural problem — which is why there is no burger here. Hiding three
   destinations behind a tap costs discoverability (NN/g measure it), a button
   with its focus and escape handling, and a decorative glyph this world bans,
   to reclaim height ONCE: the header is static, it scrolls away and never
   returns. Only the tracking gives way, and only on the phone. */
.te98377 ul{gap:10px;font-size:.85rem;letter-spacing:.07em;flex-wrap:wrap}
/* The département entry is a convenience; on a phone it would push the brand
   onto two lines. Only where a breadcrumb already carries it. */
body:has([data-fil]) .te98377 li:last-child{display:none}
.i431c3f{padding:26px var(--marge) 24px}
[data-foot-grid]{grid-template-columns:1fr 1fr}
[data-graph-plot]{height:170px}
table{font-size:1rem}
/* A dropped column is declared by ATTRIBUTE, carried by the header AND the
   cell, never by position. The nth-child and last-child forms of thead th used
   to do this job and produced the two worst defects the mobile audit found: a
   position follows the STRUCTURE, not the column, so it drifts the moment a
   column is added elsewhere, and it silently stops matching the cell it was
   paired with. data-typo-prix now sits on both, so they can only vanish
   together. Guarded by frimmo-mobile-integrite.test.ts. */
[data-typo-prix]{display:none}
[data-entete],[data-ligne]{grid-template-columns:minmax(0,1fr) 6.5rem 4.5rem}
[data-entete] span:nth-child(4),[data-c-n]{display:none}
[data-stat-val]{font-size:clamp(2rem,9vw,2.6rem)}
}
@media (max-width:620px){
/* The sample stays. data-annee-n and data-q-n used to be dropped here,
   which took the number of sales off every phone: the commune's yearly table
   kept a "Ventes" header over nothing, and the département's table — two
   columns wide — lost the only column it had and rendered empty under its own
   heading. No median is published on this site without the sales it rests on,
   so the column is kept and the band scrolls instead. */
[data-typo-bar]{display:none}
/* Fixed layout exists to stop the price column zig-zagging when several columns
   are in play. At this width only three survive, and fixed thirds gave the price
   64 px for a 75 px figure — it overflowed its cell. Auto sizes to the content
   and there is no longer enough variety left to zig-zag. */
[data-quartiers] table{table-layout:auto}
/* The gap keeps its sign and loses its sentence: four columns and a clause do
   not fit at 390 px, and the sign is what stops the direction being carried by
   colour alone. */
[data-cmp-suite]{display:none}
[data-cmp-txt]{white-space:nowrap}
[data-entete],[data-ligne]{grid-template-columns:minmax(0,1fr) 6rem;gap:10px}
[data-entete] span:nth-child(3),[data-entete] span:nth-child(4),[data-c-n],[data-c-rdt]{display:none}
/* At this width the postal code costs the price its own column. */
[data-cherche-liste] a{grid-template-columns:minmax(0,1fr) 6rem}
[data-o-cp]{display:none}
[data-dpe-item]{gap:6px}
}
/* scroll-behavior belongs here too. It is not an animation or a transition, so
   the wildcard above never touched it, and every anchor jump on a page that
   runs past 8 000 px stayed a long smooth ride whatever the reader had asked
   the system for. The subnav does its own scrolling in bandes.js, which reads
   the same query. */
@media (prefers-reduced-motion:reduce){*{animation:none !important;transition:none !important}html{scroll-behavior:auto}}
