/* Gothic Quarter Rooms — editorial travel-guide design */

@font-face {
    font-family: "Fraunces Variable";
    font-style: normal;
    font-display: swap;
    font-weight: 100 900;
    src: url("/static/fonts/fraunces-latin-wght-normal.woff2") format("woff2-variations"),
         url("/static/fonts/fraunces-latin-wght-normal.woff2") format("woff2");
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+2000-206F, U+20AC;
}
@font-face {
    font-family: "Fraunces Variable";
    font-style: normal;
    font-display: swap;
    font-weight: 100 900;
    src: url("/static/fonts/fraunces-latin-ext-wght-normal.woff2") format("woff2-variations"),
         url("/static/fonts/fraunces-latin-ext-wght-normal.woff2") format("woff2");
    unicode-range: U+0100-024F, U+1E00-1EFF;
}
@font-face {
    font-family: "Fraunces Variable";
    font-style: italic;
    font-display: swap;
    font-weight: 100 900;
    src: url("/static/fonts/fraunces-latin-wght-italic.woff2") format("woff2-variations"),
         url("/static/fonts/fraunces-latin-wght-italic.woff2") format("woff2");
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+2000-206F, U+20AC;
}
@font-face {
    font-family: "Fraunces Variable";
    font-style: italic;
    font-display: swap;
    font-weight: 100 900;
    src: url("/static/fonts/fraunces-latin-ext-wght-italic.woff2") format("woff2-variations"),
         url("/static/fonts/fraunces-latin-ext-wght-italic.woff2") format("woff2");
    unicode-range: U+0100-024F, U+1E00-1EFF;
}
@font-face {
    font-family: "Work Sans";
    font-style: normal;
    font-display: swap;
    font-weight: 400;
    src: url("/static/fonts/work-sans-latin-400-normal.woff2") format("woff2");
    unicode-range: U+0000-00FF, U+2000-206F, U+20AC;
}
@font-face {
    font-family: "Work Sans";
    font-style: normal;
    font-display: swap;
    font-weight: 400;
    src: url("/static/fonts/work-sans-latin-ext-400-normal.woff2") format("woff2");
    unicode-range: U+0100-024F, U+1E00-1EFF;
}
@font-face {
    font-family: "Work Sans";
    font-style: normal;
    font-display: swap;
    font-weight: 500;
    src: url("/static/fonts/work-sans-latin-500-normal.woff2") format("woff2");
    unicode-range: U+0000-00FF, U+2000-206F, U+20AC;
}
@font-face {
    font-family: "Work Sans";
    font-style: normal;
    font-display: swap;
    font-weight: 500;
    src: url("/static/fonts/work-sans-latin-ext-500-normal.woff2") format("woff2");
    unicode-range: U+0100-024F, U+1E00-1EFF;
}
@font-face {
    font-family: "Work Sans";
    font-style: normal;
    font-display: swap;
    font-weight: 600;
    src: url("/static/fonts/work-sans-latin-600-normal.woff2") format("woff2");
    unicode-range: U+0000-00FF, U+2000-206F, U+20AC;
}
@font-face {
    font-family: "Work Sans";
    font-style: normal;
    font-display: swap;
    font-weight: 600;
    src: url("/static/fonts/work-sans-latin-ext-600-normal.woff2") format("woff2");
    unicode-range: U+0100-024F, U+1E00-1EFF;
}
@font-face {
    font-family: "Work Sans";
    font-style: normal;
    font-display: swap;
    font-weight: 700;
    src: url("/static/fonts/work-sans-latin-700-normal.woff2") format("woff2");
    unicode-range: U+0000-00FF, U+2000-206F, U+20AC;
}
@font-face {
    font-family: "Work Sans";
    font-style: normal;
    font-display: swap;
    font-weight: 700;
    src: url("/static/fonts/work-sans-latin-ext-700-normal.woff2") format("woff2");
    unicode-range: U+0100-024F, U+1E00-1EFF;
}

:root {
    /* Palette: warm limestone, wrought iron, candlelight brass, oxblood accent */
    --ink:            #211c16;
    --ink-soft:       #58493a;
    --parchment:      #f5efe1;
    --parchment-deep: #eae0c8;
    --parchment-line: #d9c9a6;
    --oxblood:        #8a2e34;
    --oxblood-deep:   #6c2229;
    --brass:          #a9822f;
    --brass-light:    #cba24f;
    --cream:          #fbf8f0;
    --line-on-ink:    rgba(245, 239, 225, 0.16);

    --font-display: "Fraunces Variable", "Iowan Old Style", "Palatino Linotype", serif;
    --font-body: "Work Sans", "Segoe UI", sans-serif;

    --space-3xs: 0.25rem;
    --space-2xs: 0.5rem;
    --space-xs: 0.75rem;
    --space-sm: 1rem;
    --space-md: 1.5rem;
    --space-lg: 2.25rem;
    --space-xl: 3.5rem;
    --space-2xl: 5.5rem;

    --radius: 3px;
    --max-content: 1180px;
    --max-prose: 44rem;

    --ease: cubic-bezier(0.4, 0, 0.2, 1);
}

*, *::before, *::after { box-sizing: border-box; }

html {
    font-size: 16px;
    scroll-behavior: smooth;
}

body {
    margin: 0;
    font-family: var(--font-body);
    font-size: 1.0625rem;
    color: var(--ink);
    background-color: var(--parchment);
    line-height: 1.65;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

img { max-width: 100%; display: block; }

/* Typography */
h1, h2, h3, h4 {
    font-family: var(--font-display);
    font-weight: 560;
    line-height: 1.12;
    color: var(--ink);
    margin: 0 0 var(--space-sm);
    letter-spacing: -0.01em;
}

h1 { font-size: 2.25rem; }
h2 { font-size: 1.75rem; }
h3 { font-size: 1.3rem; }
h4 { font-size: 1.05rem; }

p { margin: 0 0 var(--space-sm); color: var(--ink-soft); }
p:last-child { margin-bottom: 0; }

a { color: var(--oxblood); text-decoration: none; }
a:hover { color: var(--oxblood-deep); }

ul { padding-left: 1.2em; color: var(--ink-soft); }
li { margin-bottom: var(--space-2xs); }

.eyebrow {
    display: inline-block;
    font-family: var(--font-display);
    font-style: italic;
    font-size: 1.05rem;
    color: var(--oxblood);
    margin-bottom: var(--space-2xs);
}

.rule {
    width: 44px;
    height: 2px;
    background: var(--brass);
    border: none;
    margin: 0 0 var(--space-sm);
}

.container {
    width: 100%;
    max-width: var(--max-content);
    margin: 0 auto;
    padding: 0 var(--space-md);
}

/* Vertical rhythm only — deliberately longhand. The padding shorthand
   (previously `padding: var(--space-xl) 0`) reset the horizontal padding to
   zero and, sharing the same specificity as `.container` but appearing later
   in the sheet, it silently won on every `<section class="section container">`.
   That left the listing, FAQ and similar-hotels sections flush against the
   viewport edges with no left/right gap. Longhands keep the container gutters
   intact while still supplying the section's top/bottom breathing room. */
.section {
    padding-top: var(--space-lg);
    padding-bottom: var(--space-lg);
}
.section-head {
    max-width: 40rem;
    margin: 0 0 var(--space-lg);
}
.section-head.center { margin-left: auto; margin-right: auto; text-align: center; }

.text-center { text-align: center; }

/* ---------- Header ---------- */
header {
    background-color: var(--parchment);
    border-bottom: 1px solid var(--parchment-line);
    position: sticky;
    top: 0;
    z-index: 100;
}

/* Vertical rhythm only — intentionally longhand, for the same reason as
   `.section` further down the sheet: the `padding: 1.05rem 0` shorthand reset
   the `.container` horizontal padding to zero, pushing the logo and the mobile
   menu button flush against the viewport edges and 24px out of line with the
   page content below. */
.header-inner {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding-top: 1.05rem;
    padding-bottom: 1.05rem;
}

/* Inline SVG sprite holding the brand mark (see templates/base.html) */
.brand-sprite {
    position: absolute;
    width: 0;
    height: 0;
    overflow: hidden;
}

/* Brand lockup: Gothic arch mark + two-line wordmark (no italics) */
.logo {
    display: inline-flex;
    align-items: center;
    gap: 0.7rem;
    color: var(--ink);
    line-height: 1;
}

.logo-mark {
    width: 32px;
    height: 38px;
    flex: none;
    color: var(--oxblood);
    transition: color 0.2s var(--ease);
}

.logo-text {
    display: flex;
    flex-direction: column;
    gap: 0.28rem;
}

.logo-name {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: 1.3rem;
    letter-spacing: -0.01em;
    line-height: 1;
    color: var(--ink);
    transition: color 0.2s var(--ease);
}

.logo-sub {
    font-family: var(--font-body);
    font-size: 0.62rem;
    font-weight: 600;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    line-height: 1;
    color: var(--ink-soft);
}

.logo:hover .logo-name { color: var(--oxblood); }
.logo:hover .logo-mark { color: var(--brass); }

@media (max-width: 400px) {
    .logo { gap: 0.55rem; }
    .logo-mark { width: 27px; height: 32px; }
    .logo-name { font-size: 1.15rem; }
    .logo-sub { font-size: 0.55rem; letter-spacing: 0.13em; }
}

/* Scoped to the header so the shared nav styles never leak into other
   <nav> landmarks such as the breadcrumb trail. */
header nav ul {
    display: flex;
    list-style: none;
    gap: var(--space-lg);
    margin: 0;
    padding: 0;
}

header nav a {
    position: relative;
    color: var(--ink-soft);
    font-size: 0.95rem;
    min-height: 44px;
    display: flex;
    align-items: center;
}

header nav a::after {
    content: "";
    position: absolute;
    left: 0;
    bottom: 12px;
    width: 100%;
    height: 1px;
    background: var(--oxblood);
    transform: scaleX(0);
    transform-origin: left;
    transition: transform 0.2s var(--ease);
}

/* ---------- Skip to main content link ---------- */
.skip-link {
    position: absolute;
    top: -100px;
    left: var(--space-md);
    background: var(--oxblood);
    color: var(--cream);
    padding: var(--space-xs) var(--space-sm);
    z-index: 9999;
    font-weight: 600;
    font-size: 0.95rem;
    border-radius: var(--radius);
    text-decoration: none;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
    transition: top 0.2s ease;
}
.skip-link:focus {
    top: var(--space-sm);
    outline: 2px solid var(--cream);
}

header nav a:hover, header nav a.active { color: var(--ink); }
header nav a:hover::after, header nav a.active::after { transform: scaleX(1); }
header nav a.active { font-weight: 600; color: var(--oxblood); }

.mobile-menu-btn {
    display: none;
    background: none;
    border: none;
    font-size: 1.4rem;
    color: var(--ink);
    cursor: pointer;
    min-height: 44px;
    min-width: 44px;
    padding: 0;
    align-items: center;
    justify-content: center;
}
.mobile-menu-btn .menu-icon-close { display: none; }
.mobile-menu-btn[aria-expanded="true"] .menu-icon-bars { display: none; }
.mobile-menu-btn[aria-expanded="true"] .menu-icon-close { display: block; }

@media (max-width: 767px) {
    .mobile-menu-btn { display: inline-flex; }
    header nav { display: none; }
    header nav.active {
        display: block;
        position: absolute;
        top: 100%;
        left: 0;
        right: 0;
        background: var(--parchment);
        border-bottom: 2px solid var(--parchment-line);
        box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1);
        padding: var(--space-sm) var(--space-md) var(--space-md);
    }
    header nav.active ul { flex-direction: column; gap: 0; }
    header nav.active a { padding: var(--space-xs) 0; border-bottom: 1px solid var(--parchment-line); }
    header nav.active a::after { display: none; }
}

/* ---------- Buttons ---------- */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5em;
    padding: 0.85rem 1.6rem;
    background-color: var(--oxblood);
    color: var(--cream);
    border: 1px solid var(--oxblood);
    border-radius: var(--radius);
    font-family: var(--font-body);
    font-size: 0.98rem;
    font-weight: 600;
    cursor: pointer;
    transition: background-color 0.2s var(--ease), border-color 0.2s var(--ease), color 0.2s var(--ease);
    min-height: 44px;
    line-height: 1;
}
.btn:hover { background-color: var(--oxblood-deep); border-color: var(--oxblood-deep); color: var(--cream); }

.btn-outline {
    background-color: transparent;
    border: 1px solid var(--ink);
    color: var(--ink);
}
.btn-outline:hover { background-color: var(--ink); color: var(--parchment); border-color: var(--ink); }

.btn-ghost {
    background: transparent;
    border: 1px solid var(--line-on-ink);
    color: var(--parchment);
}
.btn-ghost:hover { background: rgba(245,239,225,0.1); border-color: var(--parchment); color: var(--parchment); }

.btn-sm { padding: 0.55rem 1.1rem; font-size: 0.88rem; min-height: 38px; }

.link-arrow {
    color: var(--ink);
    font-weight: 600;
    font-size: 0.95rem;
    border-bottom: 1px solid var(--parchment-line);
    padding-bottom: 2px;
}
.link-arrow:hover { color: var(--oxblood); border-color: var(--oxblood); }

/* ---------- Hero ---------- */
.hero-image {
    position: relative;
    background-image: url('/static/img/hotels/hero-gothic-street.webp');
    background-image: image-set(url('/static/img/hotels/hero-gothic-street.webp') type("image/webp"), url('/static/img/hotels/hero-gothic-street.jpg') type("image/jpeg"));
    background-size: cover;
    background-position: center 30%;
    min-height: 78vh;
    display: flex;
    align-items: flex-end;
}

/* The copy sits on the photograph, so the scrim has to be dark enough for the
   brass eyebrow and the cream heading, not just for the body copy. Phone-first:
   at these widths the stack is taller than the hero's 78vh min-height, so the
   hero grows to fit it and the whole picture ends up behind type - a near-flat
   wash is what keeps every line legible (the old ramp faded to 0.1 and left the
   eyebrow on bare photo at 1.9:1). See the min-width: 768px override below for
   the roomier treatment once there is sky above the copy again. */
.hero-overlay {
    position: absolute;
    inset: 0;
    background: linear-gradient(to top, rgba(19, 15, 10, 0.9) 0%, rgba(19, 15, 10, 0.86) 62%, rgba(19, 15, 10, 0.78) 100%);
}

.hero-body {
    position: relative;
    z-index: 1;
    padding-bottom: var(--space-xl);
    max-width: 40rem;
}

.hero-image .eyebrow { color: var(--brass-light); }

.hero-image h1 {
    font-size: 2.6rem;
    color: var(--cream);
}

.hero-image p {
    font-size: 1.1rem;
    color: rgba(251, 248, 240, 0.88);
    max-width: 34rem;
    margin-bottom: var(--space-md);
}

.hero-actions { display: flex; gap: var(--space-sm); flex-wrap: wrap; margin-bottom: var(--space-md); }

.hero-search-bar {
    display: flex;
    gap: var(--space-2xs);
    margin-bottom: var(--space-sm);
    max-width: 38rem;
}
.hero-search-bar input {
    flex: 1;
    padding: 0.85rem 1.1rem;
    border: 1px solid rgba(245, 239, 225, 0.35);
    border-radius: var(--radius);
    background: rgba(22, 17, 13, 0.72);
    color: var(--cream);
    font-family: var(--font-body);
    font-size: 1rem;
    backdrop-filter: blur(6px);
}
.hero-search-bar input::placeholder {
    color: rgba(245, 239, 225, 0.7);
}
.hero-search-bar input:focus {
    outline: 2px solid var(--brass);
    background: rgba(22, 17, 13, 0.9);
}
.hero-search-bar .btn {
    white-space: nowrap;
}
@media (max-width: 580px) {
    .hero-search-bar { flex-direction: column; }
    .hero-search-bar .btn { width: 100%; }
}

.hero-quick-links {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    flex-wrap: wrap;
    font-size: 0.85rem;
}
.quick-link-label {
    color: rgba(245, 239, 225, 0.75);
    font-size: 0.82rem;
}
.hero-pill {
    display: inline-block;
    padding: 0.25rem 0.65rem;
    background: rgba(245, 239, 225, 0.12);
    border: 1px solid rgba(245, 239, 225, 0.25);
    border-radius: 999px;
    color: var(--cream);
    font-size: 0.82rem;
    text-decoration: none;
    transition: all 0.2s var(--ease);
}
.hero-pill:hover {
    background: rgba(245, 239, 225, 0.28);
    color: #fff;
    border-color: var(--brass-light);
}

/* The quick-link label and pills above are drawn for the dark home hero, where
   cream-on-photo reads. The listing page reuses them inside .simple-hero, whose
   background is light parchment, so the cream text and 12%-cream fill vanish
   (roughly 1:1 against the paper). Re-point just those two elements at the
   ink/cream/oxblood palette the rest of the light-surface UI uses. The dark
   .hero-image is deliberately left alone. */
.simple-hero .quick-link-label {
    color: var(--ink-soft);
}
.simple-hero .hero-pill {
    background: var(--cream);
    border-color: var(--parchment-line);
    color: var(--ink);
}
.simple-hero .hero-pill:hover {
    background: var(--ink);
    border-color: var(--ink);
    color: var(--cream);
}

.simple-hero {
    padding: var(--space-xl) 0 var(--space-lg);
    border-bottom: 1px solid var(--parchment-line);
    background: var(--parchment-deep);
}
.simple-hero .container { max-width: 40rem; }
.simple-hero p { font-size: 1.08rem; }

/* ---------- Intro / value props ---------- */
.value-props {
    display: grid;
    gap: var(--space-lg);
    grid-template-columns: 1fr;
}

.value-prop h3 { margin-bottom: var(--space-2xs); }
.value-prop p { font-size: 0.98rem; }

/* ---------- Rating medallion ----------
   The ring stacks three lines: the number, its "/ 10" scale and the "our score"
   qualifier. It is sized to that content — under ~66px the number is clipped at
   the top and the qualifier spills outside the ring on both axes. */
.medal {
    --size: 70px;
    width: var(--size);
    height: var(--size);
    border-radius: 50%;
    background: var(--ink);
    border: 1px solid var(--brass);
    box-shadow: 0 0 0 3px var(--parchment);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    color: var(--brass-light);
    flex-shrink: 0;
}
.medal .num {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: 1.05rem;
    line-height: 1;
}
.medal .of10 {
    font-size: 0.55rem;
    letter-spacing: 0.04em;
    line-height: 1;
    color: rgba(203, 162, 79, 0.75);
    margin-top: 2px;
}

/* ---------- Hotel cards ---------- */
.hotel-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--space-lg) var(--space-md);
    align-items: stretch;
}

.hotel-card {
    position: relative;
    display: flex;
    flex-direction: column;
    background: var(--cream);
    border: 1px solid var(--parchment-line);
    border-radius: var(--radius);
    overflow: hidden;
    box-shadow: 0 1px 2px rgba(33, 28, 22, 0.04), 0 14px 30px -22px rgba(33, 28, 22, 0.45);
    transition: transform 0.28s var(--ease), box-shadow 0.28s var(--ease), border-color 0.28s var(--ease);
}

.hotel-card:hover,
.hotel-card:focus-within {
    transform: translateY(-4px);
    border-color: rgba(169, 130, 47, 0.6);
    box-shadow: 0 2px 4px rgba(33, 28, 22, 0.05), 0 26px 44px -24px rgba(33, 28, 22, 0.55);
}

/* brass hairline that draws in across the top edge on hover */
.hotel-card::after {
    content: "";
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 2px;
    background: linear-gradient(90deg, var(--brass), var(--brass-light));
    transform: scaleX(0);
    transform-origin: left;
    transition: transform 0.35s var(--ease);
    z-index: 2;
}
.hotel-card:hover::after,
.hotel-card:focus-within::after { transform: scaleX(1); }

/* --- card media --- */
.hotel-card-media {
    position: relative;
    overflow: hidden;
    background: var(--parchment-deep);
    aspect-ratio: 16 / 10;
}

.hotel-card-image {
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform 0.6s var(--ease);
}
.hotel-card:hover .hotel-card-image,
.hotel-card:focus-within .hotel-card-image { transform: scale(1.05); }

/* bottom scrim keeps the rating medallion legible over any photo */
.hotel-card-media::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: 52%;
    background: linear-gradient(to top, rgba(19, 15, 10, 0.52), rgba(19, 15, 10, 0));
    pointer-events: none;
}

/* verbal rating chip sits on the photo, so it never competes with the text column */
.hotel-card-media .rating-badge-verbal {
    position: absolute;
    top: var(--space-sm);
    left: var(--space-sm);
    z-index: 1;
    background: rgba(251, 248, 240, 0.94);
    border-color: rgba(138, 46, 52, 0.25);
    box-shadow: 0 6px 16px -8px rgba(19, 15, 10, 0.7);
}

/* The ring size lives on .medal itself, so a card badge can never drift out of
   step with the three lines it has to hold — this rule only places it. */
.hotel-card-media .medal {
    position: absolute;
    left: var(--space-sm);
    bottom: var(--space-sm);
    z-index: 1;
    box-shadow: 0 8px 18px -6px rgba(19, 15, 10, 0.75);
}

/* --- card content: every text block is height-reserved so cards line up --- */
.hotel-card-content {
    display: flex;
    flex-direction: column;
    flex: 1;
    padding: var(--space-md);
}

.rating-badge-verbal {
    display: inline-block;
    font-size: 0.72rem;
    font-weight: 600;
    line-height: 1.3;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--oxblood);
    background: rgba(138, 46, 52, 0.08);
    border: 1px solid rgba(138, 46, 52, 0.2);
    padding: 0.16rem 0.5rem;
    border-radius: 999px;
    white-space: nowrap;
}

.card-best-for {
    font-size: 0.8rem;
    line-height: 1.45;
    color: var(--ink-soft);
    font-style: italic;
    margin: 0 0 0.5rem;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.hotel-card-title {
    font-size: 1.2rem;
    line-height: 1.25;
    margin: 0 0 0.35rem;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
.hotel-card-title a { color: var(--ink); text-decoration: none; transition: color 0.2s var(--ease); }
.hotel-card-title a:hover { color: var(--oxblood); }

.hotel-card-location {
    font-size: 0.88rem;
    color: var(--ink-soft);
    margin-bottom: var(--space-xs);
    display: flex;
    align-items: center;
    gap: 0.4em;
}
.hotel-card-location svg { flex-shrink: 0; opacity: 0.7; }

/* inside a card the address is clamped to two lines and pinned to the top */
.hotel-card .hotel-card-location {
    align-items: flex-start;
    line-height: 1.45;
    margin-bottom: var(--space-sm);
}
.hotel-card .hotel-card-location svg { margin-top: 0.3em; }

.hotel-card-location-text {
    flex: 1 1 auto;
    min-width: 0;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.hotel-card-description {
    font-size: 0.95rem;
    line-height: 1.55;
    color: var(--ink-soft);
    margin: 0 0 var(--space-sm);
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.hotel-card-features {
    --tag-h: 1.8rem;
    display: flex;
    flex-wrap: wrap;
    align-content: flex-start;
    gap: 0.4rem;
    margin-bottom: var(--space-sm);
}

.feature-tag {
    display: inline-flex;
    align-items: center;
    min-height: var(--tag-h, 1.8rem);
    border: 1px solid var(--parchment-line);
    background: var(--parchment);
    color: var(--ink-soft);
    padding: 0 0.65rem;
    border-radius: 999px;
    font-size: 0.78rem;
    line-height: 1.2;
    white-space: nowrap;
}

.hotel-card-footer {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: var(--space-sm);
    padding-top: var(--space-sm);
    border-top: 1px solid var(--parchment-line);
    margin-top: auto;
}

.hotel-card-price {
    font-family: var(--font-display);
    font-size: 1.05rem;
    line-height: 1.2;
    color: var(--ink);
    white-space: nowrap;
}

.hotel-card-footer .link-arrow {
    font-size: 0.9rem;
    white-space: nowrap;
    transition: color 0.2s var(--ease), border-color 0.2s var(--ease), transform 0.2s var(--ease);
}
.hotel-card:hover .hotel-card-footer .link-arrow,
.hotel-card:focus-within .hotel-card-footer .link-arrow {
    color: var(--oxblood);
    border-color: var(--oxblood);
    transform: translateX(3px);
}

/* Direct booking CTA beneath a card's price row. Full width so it reads as the
   primary action in the card, as a counterpart to the internal "View hotel"
   link. Scoped to the class so the listing and detail-page cards, which have no
   direct booking button, are untouched. */
.hotel-card-cta {
    width: 100%;
    margin-top: var(--space-sm);
}

/* Reserve the same number of lines for every text block once the grid has
   more than one column, so nothing inside the cards shuffles between rows.
   (On single-column mobile there is nothing to align against, so the cards
   shrink to their natural height instead.) */
@media (min-width: 640px) {
    .card-best-for { min-height: 2.9em; }
    .hotel-card-title { min-height: 2.5em; }
    .hotel-card .hotel-card-location { min-height: 2.9em; }
    .hotel-card-description { min-height: 4.65em; }
    .hotel-card-features { min-height: calc(var(--tag-h) * 2 + 0.4rem); }
}

/* Remove spinner arrows completely from all number inputs */
input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button {
    -webkit-appearance: none !important;
    margin: 0 !important;
}

input[type="number"] {
    -moz-appearance: textfield !important;
    appearance: textfield !important;
}

/* ---------- Filter bar (hotels listing) ---------- */
.filter-bar {
    /* Exposed so the quick-budget footer band can bleed to the panel edges
       without hard-coding the padding twice. */
    --filter-pad-x: 1.6rem;
    --filter-pad-y: 1.4rem;
    background: var(--parchment-deep);
    border: 1px solid var(--parchment-line);
    border-radius: var(--radius);
    padding: var(--filter-pad-y) var(--filter-pad-x);
    margin-bottom: var(--space-xl);
    box-shadow: 0 4px 16px -2px rgba(33, 28, 22, 0.05);
}

.filter-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 1.15rem;
    padding-bottom: 0.75rem;
    border-bottom: 1px solid rgba(217, 201, 166, 0.6);
}

.filter-header h2 {
    font-family: var(--font-display);
    font-size: 1.25rem;
    color: var(--ink);
    margin-bottom: 0;
    letter-spacing: -0.01em;
}

.filter-reset-link {
    font-size: 0.82rem;
    color: var(--oxblood);
    font-weight: 500;
    text-decoration: none;
    padding: 0.25rem 0.65rem;
    border-radius: var(--radius);
    background: rgba(138, 46, 52, 0.08);
    transition: all 0.15s ease;
}
.filter-reset-link:hover {
    background: rgba(138, 46, 52, 0.15);
    text-decoration: none;
}

/* The filter panel is the jump target for its own reloads: choosing a
   dropdown (or a quick-budget chip, or Apply) reloads the page to apply the
   filter, and the "clear"/"reset" links point back here. scroll-margin-top
   keeps the panel clear of the sticky header when the browser scrolls it into
   view, instead of tucking the heading underneath the header. 5.5rem matches
   the 88px the detail sidebar uses for the same header offset. */
#hotel-filters {
    scroll-margin-top: 5.5rem;
}

.filter-form {
    display: grid;
    gap: 1.15rem 1rem;
    grid-template-columns: 1fr;
    align-items: end;
}

.form-group {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
}

.form-group label {
    font-size: 0.78rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--ink-soft);
}

.form-group input,
.form-group select {
    padding: 0.6rem 0.8rem;
    border: 1px solid var(--parchment-line);
    border-radius: var(--radius);
    font-size: 0.92rem;
    font-family: var(--font-body);
    background: var(--cream);
    color: var(--ink);
    min-height: 44px;
    height: 44px;
    box-sizing: border-box;
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.form-group input::placeholder {
    color: #9c8e7e;
    opacity: 0.85;
}

.form-group input:focus,
.form-group select:focus {
    outline: none;
    border-color: var(--oxblood);
    box-shadow: 0 0 0 3px rgba(138, 46, 52, 0.12);
}

/* Custom styled select dropdowns */
.filter-form select {
    appearance: none;
    -webkit-appearance: none;
    -moz-appearance: none;
    background-color: var(--cream);
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%2358493a' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 0.85rem center;
    background-size: 11px;
    padding-right: 2.2rem;
    cursor: pointer;
}

/* Input with icon (Search) */
.input-with-icon {
    position: relative;
    display: flex;
    align-items: center;
    width: 100%;
}

.input-with-icon .field-icon {
    position: absolute;
    left: 0.85rem;
    color: var(--ink-soft);
    opacity: 0.55;
    pointer-events: none;
}

.input-with-icon input {
    width: 100%;
    padding-left: 2.35rem !important;
}

/* Price range inputs (Min - Max) */
.price-range-inputs {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    width: 100%;
}

.price-input-box {
    position: relative;
    display: flex;
    align-items: center;
    flex: 1;
    min-width: 0;
}

.price-input-box .currency-prefix {
    position: absolute;
    left: 0.75rem;
    font-size: 0.9rem;
    color: var(--ink-soft);
    font-weight: 500;
    pointer-events: none;
    user-select: none;
    opacity: 0.75;
}

.price-input-box input {
    width: 100%;
    padding-left: 1.65rem !important;
    padding-right: 0.5rem !important;
}

.price-sep {
    flex: 0 0 auto;
    min-width: 0.9rem;
    text-align: center;
    color: var(--ink-soft);
    font-weight: 500;
    opacity: 0.5;
    user-select: none;
}

/* Filter action buttons: two equal-width tracks. A grid (rather than flex
   items sized to their own labels) guarantees Reset and Apply always match
   widths — as flex items "Reset" collapsed to roughly half of "Apply
   filters". The tracks fill the group and share the 0.6rem gap used by the
   paired price inputs directly above them. */
.filter-actions {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.6rem;
    width: 100%;
    height: 44px;
}

.btn-apply {
    background: var(--oxblood);
    color: #ffffff;
    font-weight: 600;
    font-size: 0.88rem;
    padding: 0 0.85rem;
    width: 100%;
    height: 44px;
    border-radius: var(--radius);
    border: none;
    cursor: pointer;
    line-height: 1.15;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: background-color 0.15s ease, box-shadow 0.15s ease;
}

.btn-apply:hover {
    background: var(--oxblood-deep);
    box-shadow: 0 6px 14px -8px rgba(108, 34, 41, 0.7);
}

.btn-reset {
    background: transparent;
    color: var(--ink-soft);
    border: 1px solid var(--parchment-line);
    font-size: 0.88rem;
    font-weight: 500;
    padding: 0 0.85rem;
    width: 100%;
    height: 44px;
    border-radius: var(--radius);
    text-decoration: none;
    cursor: pointer;
    line-height: 1.15;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}

.btn-reset:hover {
    background: rgba(33, 28, 22, 0.05);
    border-color: var(--ink-soft);
    color: var(--ink);
}

/* Stacked layout: the actions group already spans the full panel width, so
   the two tracks simply split it evenly. */
@media (max-width: 639px) {
    .filter-bar {
        --filter-pad-x: 1.15rem;
        --filter-pad-y: 1.15rem;
    }
    .filter-actions-group { grid-column: 1 / -1; }
}

/* Quick budget chips — full-bleed footer band of the filter panel */
.budget-presets {
    display: flex;
    align-items: center;
    gap: 0.9rem;
    flex-wrap: wrap;
    margin: 1.35rem calc(-1 * var(--filter-pad-x)) calc(-1 * var(--filter-pad-y));
    padding: 1.05rem var(--filter-pad-x);
    background: rgba(217, 201, 166, 0.38);
    border-top: 1px solid var(--parchment-line);
    border-radius: 0 0 var(--radius) var(--radius);
}

.budget-preset-label {
    font-size: 0.78rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--ink-soft);
    white-space: nowrap;
}

.budget-chips-group {
    display: flex;
    gap: 0.5rem;
    flex-wrap: wrap;
}

.budget-chip {
    background: var(--cream);
    border: 1px solid var(--parchment-line);
    border-radius: 999px;
    padding: 0.35rem 0.85rem;
    font-size: 0.82rem;
    font-weight: 500;
    font-family: var(--font-body);
    color: var(--ink);
    cursor: pointer;
    transition: all 0.15s ease;
}

.budget-chip:hover {
    border-color: var(--oxblood);
    color: var(--oxblood);
    background: #fdfbf7;
    transform: translateY(-1px);
}

.budget-chip.active {
    background: var(--oxblood);
    color: var(--cream);
    border-color: var(--oxblood);
    font-weight: 600;
    box-shadow: 0 2px 6px rgba(138, 46, 52, 0.25);
}

.results-header {
    margin-bottom: var(--space-md);
}

.results-count {
    font-size: 0.95rem;
    color: var(--ink-soft);
    margin-bottom: 0;
}

/* ---------- Empty / error state ---------- */
.empty-state {
    text-align: center;
    padding: var(--space-xl) var(--space-md);
    border: 1px solid var(--parchment-line);
    border-radius: var(--radius);
    grid-column: 1 / -1;
}
.empty-state h3 { margin-bottom: var(--space-2xs); }
.empty-state p { margin-bottom: var(--space-md); }

/* ---------- Hotel detail ---------- */
.detail-hero {
    position: relative;
}
.detail-hero-image {
    width: 100%;
    height: 46vh;
    min-height: 300px;
    object-fit: cover;
}
/* The detail copy is a fixed-height block pinned to the bottom of the picture, so
   a percentage ramp is stable here - but it has to carry past the hotel name:
   the old version flattened to 0.05 above its 45% mark, which is exactly where
   the brass eyebrow and the wrapped title sit (measured 2.93:1 on a phone, under
   4.5:1 at every width up to the desktop breakpoint). The 62% stop also covers
   the narrowest phones, where a two-line title pushes the eyebrow up past the
   mid-point of a 300px-tall image that happens to be its brightest part. */
.detail-hero-overlay {
    position: absolute;
    inset: 0;
    background: linear-gradient(to top, rgba(19,15,10,0.9) 0%, rgba(19,15,10,0.66) 62%, rgba(19,15,10,0.15) 100%);
}
/* Absolutely positioned over the hero image; the `.container` half of the class
   list still supplies the max-width, the auto centring and the horizontal
   gutters, so only the vertical padding is set here. */
.detail-hero-body {
    position: absolute;
    left: 0; right: 0; bottom: 0;
    padding-top: var(--space-lg);
    padding-bottom: var(--space-lg);
}
.detail-hero-body h1 { color: var(--cream); font-size: 2rem; margin-bottom: 0.35rem; }
.detail-hero-body .hotel-card-location { color: rgba(251,248,240,0.85); }

/* Longhand vertical padding again: this element is also a `.container`, so a
   two-value shorthand would cancel the horizontal gutters and run the article
   copy and the sidebar flush against the viewport edges. */
.detail-layout {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--space-xl);
    padding-top: var(--space-xl);
    padding-bottom: var(--space-xl);
}

.detail-main h2 { font-size: 1.4rem; margin-top: var(--space-lg); }
.detail-main h2:first-child { margin-top: 0; }
.detail-main p { max-width: var(--max-prose); }

/* Amenities read as one checklist, not a mosaic of ragged columns. The old
   rule used `minmax(160px, 1fr)`, which packed three or four ~170px tracks
   into the desktop article column (~717px at 1440px wide), so almost every
   label broke mid-phrase ("Infinity Rooftop / Pool (guests only)") and the
   tracks short enough to hold a short label left a ragged, half-empty last
   row. Two columns is the widest split that still keeps the list compact:
   ~345px per column clears even the longest label in the data (43 characters)
   on one line, so the rows line up instead of staggering. */
.amenity-list {
    display: grid;
    grid-template-columns: 1fr;
    gap: 0.55rem 2rem;
    list-style: none;
    padding: 0;
    margin: var(--space-sm) 0 0;
}
.amenity-list li {
    display: flex;
    /* The tick rides the first line. Centring it on the flex line (the old
       value) pushed it down beside the second line of a wrapped label, so the
       item looked as if it started halfway through its own text. */
    align-items: flex-start;
    gap: 0.5em;
    font-size: 0.95rem;
    line-height: 1.5;
    color: var(--ink-soft);
    margin-bottom: 0;
}
.amenity-list svg {
    color: var(--brass);
    flex-shrink: 0;
    /* Optically centres the 15px icon on the cap height of the first line
       rather than on the line box, which keeps every tick in a straight row
       across the grid even when a label wraps. */
    margin-top: 0.3em;
}

/* Two columns from the tablet breakpoint up; the extra row gap on desktop
   gives the list the same breathing room as the prose above it. */
@media (min-width: 640px) {
    .amenity-list { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (min-width: 900px) {
    .amenity-list { gap: 0.65rem 2.25rem; }
}

.detail-sidebar {
    align-self: start;
}

.fact-panel {
    background: var(--parchment-deep);
    border: 1px solid var(--parchment-line);
    border-radius: var(--radius);
    padding: var(--space-md);
    box-shadow: inset 0 1px 0 rgba(251, 248, 240, 0.6);
}

/* Each fact is a stacked label/value pair rather than a two-up row: the short
   values keep a tidy spec-sheet rhythm on one line, while long values (e.g.
   "Best for") get the full panel width and wrap flush-left. Previously the
   value was right-aligned in a squeezed column, so a wrapping label left a
   hole beside it and long values broke into a ragged-left block. */
.fact-row {
    display: grid;
    gap: 0.25rem;
    padding: var(--space-xs) 0;
    border-bottom: 1px solid var(--parchment-line);
}
.fact-row:first-child { padding-top: 0; }
.fact-row:last-of-type { border-bottom: none; padding-bottom: 0; }

/* Micro overline, matching .form-group label / .budget-preset-label */
.fact-label {
    font-size: 0.72rem;
    font-weight: 600;
    line-height: 1.4;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--ink-soft);
}

.fact-value {
    font-family: var(--font-display);
    font-size: 1.05rem;
    line-height: 1.35;
    color: var(--ink);
    text-wrap: pretty;
    overflow-wrap: break-word;
}

/* The score carries the row, so it steps up out of the body size */
.fact-value strong { font-weight: 600; font-size: 1.2rem; line-height: 1.2; }

.fact-unit {
    font-family: var(--font-body);
    font-size: 0.78rem;
    color: var(--ink-soft);
}

.fact-panel .btn { width: 100%; margin-top: var(--space-md); }

/* Airport transfer tip block in the hotel sidebar. Sits beneath the booking
   CTA, visually separated by a top border so it reads as a related but
   distinct suggestion rather than part of the booking flow. */
.sidebar-transfer-tip {
    margin-top: var(--space-md);
    padding-top: var(--space-md);
    border-top: 1px solid var(--parchment-line);
}
.sidebar-transfer-label {
    margin: 0 0 0.3rem;
    font-size: 0.8rem;
    font-weight: 600;
    color: var(--ink-secondary);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.sidebar-transfer-link {
    display: inline-flex;
    align-items: center;
    gap: 0.2rem;
    font-size: 0.9rem;
    font-weight: 600;
    color: var(--brass);
    text-decoration: none;
}
.sidebar-transfer-link:hover { text-decoration: underline; }
.sidebar-transfer-tip .fact-dated { margin-top: 0.35rem; }

/* Reassurance fine print under the CTA. Each claim sits on its own centred
   line: previously the three claims shared one paragraph, so the last one
   wrapped awkwardly ("No added / booking fee"). */
.fact-note {
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
    font-size: 0.75rem;
    line-height: 1.5;
    color: var(--ink-soft);
    text-align: center;
    margin-top: var(--space-xs);
}

@media (min-width: 900px) {
    /* Sticky, so the CTA rides along the long article, but capped to the height
       of the window. A sticky box that is taller than the viewport cannot be
       scrolled to, so its lower half is simply unreachable: at 1024x640 the
       panel measures 651px against a 640px viewport, which clipped the
       affiliate disclosure that has to sit beside the button. The cap keeps the
       button and its disclosure reachable at any window height; on a tall
       window it never binds and no inner scrollbar appears. `dvh` is listed
       second so tablets do not size against a viewport that hides browser
       chrome. The 900px floor matches `.detail-layout`: below it the panel sits
       under the article in a single column, where sticky has no room to travel
       and the mobile dock carries the CTA instead. */
    .detail-sidebar {
        position: sticky;
        top: 88px;
        max-height: calc(100vh - 88px - var(--space-md));
        max-height: calc(100dvh - 88px - var(--space-md));
        overflow-x: hidden;
        overflow-y: auto;
        overscroll-behavior: contain;
    }
}

/* ---------- Breadcrumbs ---------- */
/* Full-bleed strip; the inner .container keeps the trail aligned with the
   rest of the page content (no half-width background band). */
.breadcrumb-nav {
    background: var(--parchment);
    border-bottom: 1px solid var(--parchment-line);
}
.breadcrumb-list {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.7rem;
    list-style: none;
    margin: 0;
    padding: 0.7rem 0;
    font-size: 0.75rem;
    font-weight: 500;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--ink-soft);
}
.breadcrumb-list li {
    display: inline-flex;
    align-items: center;
    gap: 0.7rem;
    margin: 0;
}
/* Separator chevrons are drawn in CSS so the markup stays a clean list.
   (The display:none guard neutralises the legacy "<li class="separator">›</li>"
   nodes still present in HTML cached/served by an older build.) */
.breadcrumb-list .separator { display: none; }
.breadcrumb-list li + li::before {
    content: "";
    flex: none;
    width: 5px;
    height: 5px;
    border-top: 1px solid var(--brass);
    border-right: 1px solid var(--brass);
    transform: rotate(45deg);
    opacity: 0.8;
}
.breadcrumb-list a {
    color: var(--ink-soft);
    text-decoration: none;
    border-bottom: 1px solid transparent;
    padding-bottom: 1px;
    transition: color 0.2s var(--ease), border-color 0.2s var(--ease);
}
.breadcrumb-list a:hover,
.breadcrumb-list a:focus-visible {
    color: var(--oxblood);
    border-bottom-color: var(--brass);
}
.breadcrumb-list li[aria-current="page"] {
    color: var(--ink);
    font-weight: 600;
}
.breadcrumb-list li[aria-current="page"] > span {
    padding-bottom: 1px;
    border-bottom: 1px solid transparent;
}

/* ---------- Proximity Walking Times ---------- */
.proximity-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
    gap: var(--space-xs);
    margin-top: var(--space-sm);
}
.proximity-item {
    background: var(--cream);
    border: 1px solid var(--parchment-line);
    border-radius: var(--radius);
    padding: var(--space-xs) var(--space-sm);
    display: flex;
    flex-direction: column;
}
.prox-time {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: 1.15rem;
    color: var(--oxblood);
}
.prox-dest {
    font-size: 0.82rem;
    color: var(--ink-soft);
    margin-top: 2px;
}
/* Verbal rating beside the score: same oxblood pill language as the cards'
   .rating-badge-verbal, shrunk to sit on the fact-value baseline. */
.verbal-fact {
    display: inline-block;
    font-family: var(--font-body);
    font-size: 0.68rem;
    font-weight: 600;
    line-height: 1.5;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--oxblood);
    background: rgba(138, 46, 52, 0.08);
    border: 1px solid rgba(138, 46, 52, 0.2);
    border-radius: 999px;
    padding: 0.1rem 0.45rem;
    white-space: nowrap;
    vertical-align: 0.08em;
}

/* ---------- Mobile Sticky Booking Dock ---------- */
/* One fixed element holding the booking bar. The wrapper exists so showing and
   hiding the bar is a single transform on one element (`main.js` toggles
   `.is-shown`), and so anything added to the bar later stacks inside it rather
   than having to be positioned against it by a hard-coded offset - which is
   what previously put the disclosure strip underneath the bar.
   The 899px limit is the point where `.detail-layout` puts the fact panel
   beside the article (see the min-width: 900px rule). Below it the price and
   the CTA sit thousands of pixels down the page behind the article, so the
   dock is the only booking affordance within reach. */
.mobile-booking-dock {
    display: none;
}
@media (max-width: 899px) {
    .mobile-booking-dock {
        display: block;
        position: fixed;
        left: 0;
        right: 0;
        bottom: 0;
        background: var(--ink);
        /* Below the sticky header (100) so an open mobile menu still wins. */
        z-index: 99;
        /* Held off-screen until main.js confirms the hero has scrolled away. */
        transform: translateY(100%);
        transition: transform 0.25s var(--ease);
    }
    .mobile-booking-dock.is-shown { transform: translateY(0); }
    /* With scripting off the class never arrives, so reveal the dock outright:
       on a phone this bar is the only booking affordance above the fold and it
       must not depend on JS to exist. */
    @media (scripting: none) {
        .mobile-booking-dock { transform: none; }
    }

    .mobile-booking-bar {
        display: flex;
        padding: 0.75rem 1rem;
        color: var(--parchment);
        border-top: 2px solid var(--brass);
        justify-content: space-between;
        align-items: center;
        box-shadow: 0 -4px 16px rgba(0, 0, 0, 0.3);
    }
    .mobile-booking-info {
        display: flex;
        flex-direction: column;
        line-height: 1.25;
    }
    .mobile-booking-name {
        font-family: var(--font-display);
        font-size: 0.95rem;
        color: var(--cream);
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
        max-width: 170px;
    }
    .mobile-booking-price {
        font-size: 0.85rem;
        color: var(--brass-light);
        font-weight: 500;
    }
    .mobile-booking-bar .btn {
        margin: 0;
        padding: 0.55rem 1.1rem;
        min-height: 38px;
        font-size: 0.88rem;
    }
}

/* ---------- Similar Hotels Section ---------- */
.similar-section {
    border-top: 1px solid var(--parchment-line);
    padding-top: var(--space-xl);
    margin-top: var(--space-xl);
}

/* ---------- FAQ Section ---------- */
.faq-section {
    border-top: 1px solid var(--parchment-line);
    margin-top: var(--space-2xl);
    padding-top: var(--space-xl);
}
.faq-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--space-md);
}
@media (min-width: 768px) {
    .faq-grid {
        grid-template-columns: repeat(2, 1fr);
    }
}
.faq-item {
    background: var(--cream);
    border: 1px solid var(--parchment-line);
    border-radius: var(--radius);
    padding: var(--space-md);
}
.faq-item h3 {
    font-size: 1.12rem;
    margin-bottom: var(--space-xs);
    color: var(--ink);
}
.faq-item p {
    font-size: 0.95rem;
    line-height: 1.6;
    margin: 0;
}

/* ---------- CTA band ---------- */
/* Closing call-to-action. A warm parchment wash that deepens toward the ink
   footer below, so the band reads as a deliberate end-of-page moment instead
   of a flat black slab. It sits flush against the footer: page sections
   already carry the closing whitespace, and a footer margin would expose the
   body's parchment background as a stray light strip between the two. */
.cta-band {
    position: relative;
    background:
        radial-gradient(120% 90% at 50% 0%, rgba(203, 162, 79, 0.16) 0%, rgba(203, 162, 79, 0) 58%),
        linear-gradient(180deg, var(--parchment) 0%, var(--parchment-deep) 55%, #e3d5b6 100%);
    border-top: 1px solid var(--parchment-line);
    color: var(--ink);
    padding: var(--space-xl) 0 calc(var(--space-xl) + var(--space-2xs));
    text-align: center;
}
.cta-band .rule { margin-left: auto; margin-right: auto; }
.cta-band h2 { color: var(--ink); margin-bottom: var(--space-2xs); }
.cta-band p {
    color: var(--ink-soft);
    max-width: 34rem;
    margin: 0 auto;
}
.cta-band .btn { margin-top: var(--space-md); }
.cta-band .cta-band-back { margin-top: var(--space-md); }
.cta-band .link-arrow { color: var(--ink-soft); border-color: var(--parchment-line); }
.cta-band .link-arrow:hover { color: var(--oxblood); border-color: var(--brass); }

/* ---------- Prose pages (about/contact/privacy/terms) ---------- */
.prose {
    max-width: var(--max-prose);
    margin: 0 auto;
    padding: var(--space-xl) 0 var(--space-2xl);
}
.prose h1 { margin-bottom: var(--space-md); padding-bottom: var(--space-md); border-bottom: 1px solid var(--parchment-line); }
.prose h2 { margin-top: var(--space-lg); }
.prose ul { margin-bottom: var(--space-sm); }

/* ---------- Prose tables (guide comparison tables) ---------- */
/* Guide bodies render Markdown pipe tables as plain <table> with no wrapper,
   so the table itself has to scroll: block + overflow-x keeps a 5-column
   compare table inside the 44rem prose column on a 360px phone instead of
   blowing the layout out. Header row picks up the parchment tone so a table
   reads as a table even before the reader parses the columns. */
.prose table {
    display: block;
    width: 100%;
    max-width: 100%;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    border-collapse: collapse;
    margin: var(--space-md) 0;
    font-size: 0.86rem;
    line-height: 1.5;
}
.prose th,
.prose td {
    padding: 0.55rem 0.7rem;
    border: 1px solid var(--parchment-line);
    text-align: left;
    vertical-align: top;
    min-width: 7rem;
}
.prose th {
    background: var(--parchment-deep);
    font-weight: 600;
    white-space: nowrap;
}
.prose td a { font-weight: 500; }

/* ---------- Error page ---------- */
.error-page {
    text-align: center;
    padding: var(--space-2xl) var(--space-md);
    max-width: 32rem;
    margin: 0 auto;
}
.error-page .eyebrow { display: block; font-size: 3rem; margin-bottom: var(--space-sm); }

/* ---------- Footer ---------- */
/* No top margin: the closing page section (`.section`, `.prose` or
   `.error-page`) already provides the whitespace above. A margin here only
   leaked the body's parchment background through as a light strip between the
   dark CTA band and the footer. */
footer {
    background-color: var(--ink);
    color: rgba(245, 239, 225, 0.7);
    padding: var(--space-xl) 0 var(--space-md);
}

.footer-content {
    display: grid;
    gap: var(--space-lg);
    grid-template-columns: 1fr;
    padding-bottom: var(--space-lg);
    border-bottom: 1px solid var(--line-on-ink);
}

.footer-brand {
    display: inline-flex;
    align-items: center;
    gap: 0.6rem;
    font-family: var(--font-display);
    font-weight: 600;
    font-size: 1.15rem;
    line-height: 1.1;
    color: var(--cream);
    margin-bottom: var(--space-2xs);
}

.footer-brand-mark {
    width: 25px;
    height: 30px;
    flex: none;
    color: var(--brass-light);
}

.footer-section h4 {
    color: var(--cream);
    font-size: 0.95rem;
    margin-bottom: var(--space-sm);
    font-family: var(--font-body);
    font-weight: 600;
}

/* The global `p` rule sets --ink-soft, which a direct declaration always
   applies over the inherited footer colour. Restate a light tone on ink. */
.footer-section p {
    color: rgba(245, 239, 225, 0.78);
    max-width: 34rem;
}

.footer-section a {
    color: rgba(245, 239, 225, 0.7);
    display: block;
    margin-bottom: var(--space-xs);
}
.footer-section a:hover { color: var(--brass-light); }

.footer-bottom {
    padding-top: var(--space-md);
    text-align: left;
    font-size: 0.85rem;
}
.footer-bottom p { color: rgba(245, 239, 225, 0.55); margin-bottom: 0.35rem; }

/* ---------- Responsive ---------- */
@media (min-width: 640px) {
    .value-props { grid-template-columns: repeat(3, 1fr); }
    .hotel-grid { grid-template-columns: repeat(2, 1fr); }
    .filter-form { grid-template-columns: repeat(2, 1fr); }
}

@media (min-width: 768px) {
    h1 { font-size: 2.75rem; }
    h2 { font-size: 2rem; }
    .hero-image h1 { font-size: 3.4rem; }
    .hero-image { min-height: 84vh; }
    /* Once the copy no longer fills the hero there is photo to show above it, so
       the wash eases back into a ramp. The band is anchored in rem rather than %
       because it spans the copy stack (eyebrow to the filter pills), which is a
       fixed height here: 26rem covers it and holds ~0.8 behind the eyebrow at
       every width, including short landscape windows where a % ramp would leave
       the eyebrow up in the light end of the gradient. */
    .hero-overlay {
        background: linear-gradient(to top, rgba(19, 15, 10, 0.9) 0, rgba(19, 15, 10, 0.8) 26rem, rgba(19, 15, 10, 0.35) 100%);
    }
    .detail-hero-image { height: 54vh; }
    .detail-hero-body h1 { font-size: 2.75rem; }
    /* Two groups per row: four tracks only have room for the longest guide
       title in "Plan your stay" from 900px, where the footer goes to a single
       row of four (see that block). */
    .footer-content { grid-template-columns: 1.3fr 1fr; }
}

@media (min-width: 900px) {
    .detail-layout { grid-template-columns: 2fr 1fr; }
    .filter-form { grid-template-columns: repeat(3, 1fr); }
    /* All four groups — brand, Explore, Plan your stay, Legal — in one row.
       The three link columns are sized to their own longest entry and the brand
       takes the remainder, so the row runs edge to edge: an fr split would
       leave roughly 200px of slack to be scattered over the row as dead
       gutters. Brand copy is capped at 34rem, so what is left over shows as the
       deliberately wider gap that sets the blurb apart from the navigation.
       The gutter drops from --space-lg to --space-md now that the row carries
       three gaps instead of two. */
    .footer-content {
        grid-template-columns: minmax(0, 1fr) max-content max-content max-content;
        gap: var(--space-md);
    }
}

@media (min-width: 1024px) {
    .hotel-grid { grid-template-columns: repeat(3, 1fr); }
}

/* Accessibility */
@media (prefers-reduced-motion: reduce) {
    * { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; scroll-behavior: auto !important; }
}

a:focus-visible, button:focus-visible, input:focus-visible, select:focus-visible {
    outline: 2px solid var(--oxblood);
    outline-offset: 2px;
}

@media print {
    header, footer, .btn, .fact-panel .btn { display: none; }
}

/* Qualifier on the rating medal. A bare "8.7 / 10" on a card reads as a guest
   score, so it is labelled as our own editorial assessment. It is set to the
   widest single line that still clears the ring, and held on one line (nowrap)
   so longer wording can never wrap and escape the circle — keep it short. */
.medal-source {
    display: block;
    font-family: var(--font-body);
    font-size: 0.5rem;
    letter-spacing: 0.04em;
    line-height: 1;
    text-transform: uppercase;
    color: rgba(255, 255, 255, 0.75);
    margin-top: 2px;
    white-space: nowrap;
}

/* ---------------------------------------------------------------------------
   Sourced hotel page components
   Added for the honest, sourced rewrite: pros/cons, room advice, practical
   details and sources.
   --------------------------------------------------------------------------- */

/* Pros and cons. Two columns on desktop, stacked on narrow screens, so the
   trade-off is read as a pair rather than as a list of upsides. */
.pc-intro {
    font-size: 0.9rem;
    color: var(--ink-soft);
    margin-top: calc(-1 * var(--space-xs));
}

.pc-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--space-md);
    margin-top: var(--space-md);
}

@media (min-width: 768px) {
    .pc-grid { grid-template-columns: 1fr 1fr; }
}

.pc-col {
    border: 1px solid var(--parchment-line);
    border-radius: 4px;
    padding: var(--space-sm) var(--space-md) var(--space-md);
    background: rgba(255, 255, 255, 0.5);
}

.pc-heading {
    display: flex;
    align-items: center;
    gap: var(--space-2xs);
    font-size: 0.82rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    margin-bottom: var(--space-xs);
}

.pc-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.4rem;
    height: 1.4rem;
    border-radius: 50%;
    flex-shrink: 0;
}

.pc-pros .pc-heading { color: var(--oxblood); }
.pc-pros .pc-icon { background: rgba(138, 46, 52, 0.12); color: var(--oxblood); }

.pc-cons .pc-heading { color: var(--ink-soft); }
.pc-cons .pc-icon { background: rgba(88, 73, 58, 0.12); color: var(--ink-soft); }

.pc-col ul { list-style: none; margin: 0; padding: 0; }

.pc-col li {
    position: relative;
    padding-left: var(--space-sm);
    margin-bottom: var(--space-2xs);
    font-size: 0.92rem;
    line-height: 1.55;
}

.pc-col li:last-child { margin-bottom: 0; }

/* A small marker rather than a bullet, so the two columns read differently
   at a glance even for a skim-reader. */
.pc-col li::before {
    position: absolute;
    left: 0;
    top: 0;
    color: var(--brass);
    font-weight: 700;
}
.pc-pros li::before { content: "+"; }
.pc-cons li::before { content: "\2212"; color: var(--ink-soft); }

/* Room advice and practical details. */
.practical-list {
    list-style: none;
    margin: var(--space-sm) 0 0;
    padding: 0;
    border-top: 1px solid var(--parchment-line);
}

.practical-list li {
    padding: var(--space-xs) 0;
    border-bottom: 1px solid var(--parchment-line);
    font-size: 0.92rem;
    line-height: 1.55;
}

/* The date line under the rating and the price band. */
.fact-dated {
    margin: 0 0 var(--space-xs);
    font-size: 0.78rem;
    line-height: 1.5;
    color: var(--ink-soft);
}

@media (max-width: 899px) {
    /* Reserve room for the dock so it never covers the last line of the page.
       5rem clears the 64px bar with slack for the 75px it measures at 320px
       wide, where the price wraps onto a second line. */
    body:has(.mobile-booking-dock) {
        padding-bottom: calc(5rem + env(safe-area-inset-bottom));
    }
}


/* ---------- Guide lists (guides hub, single guide pages, homepage) ---------- */
/* The guide pages are the landing pages that carry the SEO work, so their link
   lists are deliberately substantial: a title a reader can scan, and the intro
   as a one-line reason to click. Reusing the card language (cream panel,
   parchment rule, brass accent on hover) keeps them part of the same site
   rather than looking like a bolted-on blog. */
.guide-list {
    list-style: none;
    display: grid;
    gap: var(--space-sm);
    margin: 0;
    padding: 0;
    grid-template-columns: 1fr;
}

.guide-list li {
    background: var(--cream);
    border: 1px solid var(--parchment-line);
    border-radius: var(--radius);
    padding: var(--space-md);
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    /* A panel that only underlines its title on hover gives no hint that the
       whole box is one object, so the card lifts and its edge warms to brass
       the way .hotel-card does. */
    transition: border-color 0.2s var(--ease), box-shadow 0.2s var(--ease), transform 0.2s var(--ease);
}

.guide-list li:hover,
.guide-list li:focus-within {
    border-color: var(--brass);
    box-shadow: 0 12px 24px -20px rgba(19, 15, 10, 0.9);
    transform: translateY(-2px);
}

.guide-list a {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: 1.08rem;
    line-height: 1.3;
    color: var(--oxblood);
    /* The underline is a text-decoration rather than the border-bottom used by
       .link-arrow and .breadcrumb-list a. Those are content-width inline
       elements, so a border hugs the text; this anchor is a stretched flex item
       of a column flex container, so a border would run the full width of the
       card and underline the empty space beside the title. text-decoration
       follows the glyphs instead, which also keeps a wrapped two-line title
       correct. The colour starts transparent so revealing it on hover shifts
       nothing. */
    text-decoration: underline;
    text-decoration-color: transparent;
    text-decoration-thickness: 1px;
    text-underline-offset: 0.18em;
    transition: color 0.2s var(--ease), text-decoration-color 0.2s var(--ease);
}

.guide-list a:hover,
.guide-list a:focus-visible {
    color: var(--oxblood-deep);
    text-decoration-color: var(--oxblood);
}

.guide-list span {
    font-size: 0.92rem;
    line-height: 1.55;
    color: var(--ink-soft);
    margin: 0;
    /* Same reason as .fact-value: keeps a single short word off the last line
       of a three- or four-line intro. */
    text-wrap: pretty;
}

/* The compact variant is a planned-reading index: the articles a reader needs
   before booking, used under the homepage collection cards where the intros
   would only repeat what each card already says. Panels were the wrong shape
   for it twice over - a second grid of cards directly under the first reads as
   one long wall of boxes, and a barer list of bare links reads as leftover
   text that never got styled. Ruled rows do the job the cards do, because each
   title is visibly its own object, without repeating the panel. */
.guide-list-compact {
    margin-top: var(--space-md);
    /* The rules and the row padding carry the vertical rhythm here, so the rows
       sit flush and only the column gap is needed. The closing rule is the
       list's own bottom edge, which stops the last row reading as if the index
       had simply run out. */
    gap: 0 var(--space-md);
    border-bottom: 1px solid var(--parchment-line);
}

.guide-list-compact li {
    /* The marker is given its own column so a two-line title hangs under its
       own first character rather than under the arrow, and baseline alignment
       holds the arrow on the title's first line whatever the fonts do. The row
       keeps no padding of its own - it is all on the <a> below, so the padding
       is inside the link and the whole row is the click target instead of just
       the words. */
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    align-items: baseline;
    column-gap: var(--space-xs);
    padding: 0;
    margin: 0;
    background: none;
    border: 0;
    border-top: 1px solid var(--parchment-line);
    border-radius: 0;
    /* No panel here, so the card's hover lift is switched off and the rule
       warming to brass is the cue that the whole row is being pointed at. */
    transform: none;
    box-shadow: none;
    transition: border-color 0.2s var(--ease);
}

.guide-list-compact li:hover,
.guide-list-compact li:focus-within {
    border-top-color: var(--brass);
}

/* A size below the collection titles: these are the supporting articles, and
   six of them in two columns at 1.08rem shout. */
.guide-list-compact a {
    font-size: 1.02rem;
    line-height: 1.35;
    padding: var(--space-sm) 0;
    /* Titles here run 30-60 characters, so a short word can otherwise be left
       alone on a second line ("...or the / Eixample?"). */
    text-wrap: balance;
}

.guide-list-compact li:hover a,
.guide-list-compact li:focus-within a {
    color: var(--oxblood-deep);
    text-decoration-color: var(--oxblood);
}

/* A brass arrow marker, hung off the <li> rather than the <a> so it can never
   end up in the link's accessible name. */
.guide-list-compact li::before {
    content: "\2192";
    font-size: 1rem;
    color: var(--brass);
    transition: color 0.2s var(--ease), transform 0.2s var(--ease);
}

.guide-list-compact li:hover::before,
.guide-list-compact li:focus-within::before {
    color: var(--oxblood);
    /* Points at where the click goes without moving the text. */
    transform: translateX(3px);
}

@media (min-width: 640px) {
    .guide-list {
        grid-template-columns: repeat(2, 1fr);
    }
    .guide-list-compact {
        grid-template-columns: repeat(2, 1fr);
    }
}

/* ---------- Homepage guides hub ---------- */
/* Two different kinds of link share this one section: the collections a reader
   books from, and the articles that answer the questions which come first.
   Previously both lists were the same left-aligned block with no break between
   them, so the article links read as a continuation of the card grid and the
   whole thing looked like a wall of boxes over a run of stray links. The hub
   fences the second group off with a parchment rule and its own head.

   The head is also wider here: at the shared 40rem the h2 broke as
   "...hotel for / your trip", leaving a two-word orphan line. 48rem clears the
   full title on one line at desktop widths, and `balance` keeps the wrap even
   whenever a narrower viewport does force it onto two. */
.guides-hub .section-head {
    max-width: 48rem;
}

.guides-hub .section-head h2 {
    text-wrap: balance;
}

.guides-hub-subhead {
    margin-top: var(--space-xl);
    padding-top: var(--space-lg);
    border-top: 1px solid var(--parchment-line);
}

.guides-hub-subhead h3 {
    margin-bottom: 0;
}

.guides-hub-cta {
    margin-top: var(--space-lg);
}


/* ---------- Hotel map (Leaflet) ---------- */
/* The map lives in two different columns: full width on the listing and the
   narrower detail column. Leaflet owns everything inside the frame, so the
   container only needs a height, a border and a stacking context. z-index: 0
   keeps Leaflet's panes (which run up to ~700 internally) under the sticky
   header, which is z-index 100: without the stacking context the map painted
   over the header as it scrolled past. */
.map-section .map-intro {
    max-width: var(--max-prose);
    margin-top: var(--space-2xs);
}

.hotel-map {
    position: relative;
    z-index: 0;
    width: 100%;
    height: 380px;
    border: 1px solid var(--parchment-line);
    border-radius: var(--radius);
    background: var(--parchment-deep);
    overflow: hidden;
}

.hotel-map-detail {
    height: 300px;
    margin: var(--space-md) 0 var(--space-lg);
}

/* Leaflet's controls are theirs, but the type can inherit ours. */
.hotel-map .leaflet-control-attribution {
    font-family: var(--font-body);
    font-size: 0.7rem;
}

.map-popup-name {
    display: block;
    margin-bottom: 0.15rem;
    font-family: var(--font-display);
    font-size: 1rem;
    color: var(--ink);
}

.map-popup-price {
    display: block;
    margin-bottom: 0.4rem;
    color: var(--ink-soft);
    font-size: 0.85rem;
}

.map-popup-link {
    font-weight: 600;
    color: var(--oxblood);
}

@media (min-width: 640px) {
    .hotel-map {
        height: 440px;
    }
    .hotel-map-detail {
        height: 320px;
    }
}

/* Editorial Callout & Contextual Guide Links */
.editorial-callout {
    background: var(--cream);
    border: 1px solid var(--parchment-line);
    border-left: 3px solid var(--oxblood);
    border-radius: var(--radius);
    padding: var(--space-md);
    margin: var(--space-lg) 0;
}
.editorial-callout.accessibility-callout {
    border-left-color: var(--brass);
}
.editorial-callout .eyebrow {
    margin-bottom: var(--space-3xs);
}
.editorial-callout h3 {
    font-family: var(--font-display);
    font-size: 1.15rem;
    margin: 0 0 var(--space-2xs);
    color: var(--ink);
}
.editorial-callout p {
    font-size: 0.95rem;
    line-height: 1.6;
    margin: 0;
    color: var(--ink-soft);
}
.editorial-callout a {
    color: var(--oxblood);
    font-weight: 500;
}

/* Card Guide Links — plain colored text, not pills/buttons */
.card-guide-tag {
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem 0.9rem;
    margin-top: var(--space-2xs);
}
.card-guide-tag a {
    display: inline;
    font-size: 0.78rem;
    font-weight: 600;
    color: var(--oxblood);
    background: none;
    border: none;
    padding: 0;
    border-radius: 0;
    text-decoration: none;
}
.card-guide-tag a:hover {
    background: none;
    color: var(--oxblood-dark, var(--oxblood));
    border: none;
    text-decoration: none;
    opacity: 0.75;
}

/* Homepage Guides Spotlight Grid */
.guides-spotlight-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--space-md);
    margin-bottom: var(--space-lg);
}
@media (min-width: 680px) {
    .guides-spotlight-grid {
        grid-template-columns: repeat(2, 1fr);
    }
}
.guide-spotlight-card {
    display: block;
    background: var(--cream);
    border: 1px solid var(--parchment-line);
    border-top: 3px solid var(--brass);
    border-radius: var(--radius);
    padding: var(--space-md);
    text-decoration: none;
    color: var(--ink);
    transition: transform 0.2s var(--ease), box-shadow 0.2s var(--ease), border-color 0.2s var(--ease);
}
.guide-spotlight-card:hover {
    transform: translateY(-2px);
    box-shadow: 0 4px 12px rgba(33, 28, 22, 0.08);
    border-top-color: var(--oxblood);
}
.guide-spotlight-card h3 {
    font-family: var(--font-display);
    font-size: 1.25rem;
    margin: var(--space-2xs) 0;
    color: var(--ink);
}
.guide-spotlight-card p {
    font-size: 0.95rem;
    line-height: 1.55;
    color: var(--ink-soft);
    margin-bottom: var(--space-xs);
}

/* Consent banner — privacy-friendly analytics gate. Fixed to the bottom so it
   never blocks content, dismissable, and the site is fully functional
   regardless. A light, low-contrast bar so it doesn't dominate the page. */
.consent-banner {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 60;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: var(--space-xs) var(--space-md);
    padding: var(--space-sm) var(--space-md);
    background: var(--parchment-deep);
    color: var(--ink-soft);
    border-top: 1px solid var(--parchment-line);
    font-family: var(--font-body);
    box-shadow: 0 -4px 16px rgba(33, 28, 22, 0.08);
}
.consent-banner .consent-text {
    margin: 0;
    font-size: 0.9rem;
    line-height: 1.5;
}
.consent-banner .consent-actions {
    display: flex;
    gap: var(--space-xs);
    flex-shrink: 0;
}
.consent-btn {
    font-family: var(--font-body);
    font-size: 0.9rem;
    font-weight: 600;
    padding: 0.45rem 1.4rem;
    border-radius: var(--radius);
    cursor: pointer;
    border: 1px solid transparent;
    transition: background-color 0.2s var(--ease), color 0.2s var(--ease), border-color 0.2s var(--ease);
}
.consent-accept {
    background: var(--oxblood);
    color: var(--cream);
    border-color: var(--oxblood);
}
.consent-accept:hover,
.consent-accept:focus-visible {
    background: var(--oxblood-deep);
    border-color: var(--oxblood-deep);
}
.consent-btn:focus-visible {
    outline: 2px solid var(--oxblood);
    outline-offset: 2px;
}
@media (max-width: 600px) {
    .consent-banner {
        flex-direction: column;
        align-items: stretch;
        text-align: center;
    }
    .consent-banner .consent-actions {
        justify-content: stretch;
    }
    .consent-btn {
        flex: 1;
    }
}

