/* Blockbook theme: "Phone book, printed." Palette, paper/stock textures and
   type from the approved mockup theme-final.html. Grain/fiber/dot SVG data
   URIs below are the exact values from that mockup (feTurbulence params
   cited in the Plan 2 brief: grain baseFrequency .85 alpha .11; fibers
   baseFrequency ".02 .4" opacity .18; header dots 6px tile, r 1.3,
   #ffffff14), not re-derived here. */

@font-face {
  font-family: "Alfa Slab One";
  src: url("fonts/alfa-slab-one-400.a67b53512e75.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Oswald";
  src: url("fonts/oswald-500.8af401f8e32b.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Oswald";
  src: url("fonts/oswald-700.665f37b2d0e8.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Work Sans";
  src: url("fonts/work-sans-400.63d1a39385c8.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Work Sans";
  src: url("fonts/work-sans-600.74474f8e77a9.woff2") format("woff2");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Work Sans";
  src: url("fonts/work-sans-700.f5bedcfff1fa.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

:root {
  --paper: #f6efdc;
  --stock: #fffdf5;
  --ink: #1b2a57;
  --mustard: #e8b93c;
  --tomato: #e2553a;
  /* WCAG AA text variant of --tomato: 4.85:1 on --paper, 5.46:1 on --stock
     (--tomato itself is 3.27:1 / 3.69:1, fails the 4.5:1 small-text
     minimum). Use --tomato-ink for any small text; keep --tomato for
     fills, shadows and large (>=19px) bold text where 3:1 suffices. */
  --tomato-ink: #b83f24;
  --butter: #f3dd96;
  --sage: #e9ebd6;
  --muted-ink: #5a513f;

  /* cream page grain (feTurbulence baseFrequency .85, alpha .11) */
  --grain-bg: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%22180%22%20height%3D%22180%22%3E%3Cfilter%20id%3D%22n%22%3E%3CfeTurbulence%20type%3D%22fractalNoise%22%20baseFrequency%3D%22.85%22%20numOctaves%3D%223%22%20stitchTiles%3D%22stitch%22/%3E%3CfeColorMatrix%20values%3D%220%200%200%200%20.35%20%200%200%200%200%20.28%20%200%200%200%200%20.15%20%200%200%200%20.11%200%22/%3E%3C/filter%3E%3Crect%20width%3D%22100%25%22%20height%3D%22100%25%22%20filter%3D%22url%28%23n%29%22/%3E%3C/svg%3E');
  /* faint page fibers (feTurbulence baseFrequency .02 .4, opacity .18) */
  --fiber-bg: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%22240%22%20height%3D%22240%22%3E%3Cfilter%20id%3D%22f%22%3E%3CfeTurbulence%20type%3D%22fractalNoise%22%20baseFrequency%3D%22.02%20.4%22%20numOctaves%3D%222%22%20seed%3D%224%22/%3E%3CfeColorMatrix%20values%3D%220%200%200%200%20.3%20%200%200%200%200%20.25%20%200%200%200%200%20.1%20%200%200%200%20-2.2%201.1%22/%3E%3C/filter%3E%3Crect%20width%3D%22100%25%22%20height%3D%22100%25%22%20filter%3D%22url%28%23f%29%22%20opacity%3D%22.18%22/%3E%3C/svg%3E');
  /* navy header halftone (6px tile, r 1.3, #ffffff14) */
  --dot-bg: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%226%22%20height%3D%226%22%3E%3Ccircle%20cx%3D%223.0%22%20cy%3D%223.0%22%20r%3D%221.3%22%20fill%3D%22%23ffffff14%22/%3E%3C/svg%3E');
}

* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  font-family: "Work Sans", Arial, sans-serif;
  font-size: 17px;
  line-height: 1.5;
  color: var(--ink);
  background-color: var(--paper);
  background-image: var(--grain-bg), var(--fiber-bg);
}

h1, h2, h3, h4, .card-title, .provider-name, .chip, button, .btn {
  font-family: Oswald, sans-serif;
}
h1, h2, h3, h4 { text-transform: uppercase; }

a { color: var(--ink); }
a:focus-visible, button:focus-visible, input:focus-visible, select:focus-visible,
.chip:focus-visible, [tabindex]:focus-visible {
  outline: 3px solid var(--tomato);
  outline-offset: 2px;
}

.site-header {
  background-color: var(--ink);
  background-image: var(--dot-bg);
  padding: 12px 16px;
}
.logo {
  font-family: "Alfa Slab One", serif;
  font-size: 32px;
  line-height: 1;
  color: var(--butter);
  text-shadow: 2px 2px 0 var(--tomato);
  text-transform: uppercase;
  letter-spacing: 1px;
  margin: 0;
}
.tagline {
  font-family: Oswald, sans-serif;
  font-size: 13px;
  letter-spacing: 2px;
  text-transform: uppercase;
  color: var(--butter);
  margin: 4px 0 0;
}

main { max-width: 1200px; margin: 0 auto; padding: 16px; }

.card, .search-box, input[type="text"], input[type="email"], input[type="search"] {
  background-color: var(--stock);
  background-image: var(--grain-bg);
  border: 2px solid var(--ink);
  color: var(--ink);
}
.card { padding: 12px 14px; box-shadow: 5px 5px 0 var(--mustard); margin-bottom: 12px; }
.card p { margin: 2px 0; }
.search-box, input[type="search"] {
  padding: 10px 12px;
  box-shadow: 3px 3px 0 var(--mustard);
  font-weight: 600;
  font-size: 17px;
  width: 100%;
}

.chip {
  display: inline-block;
  margin: 0 6px 6px 0;
  padding: 3px 10px;
  border: 2px solid var(--ink);
  text-transform: uppercase;
  font-size: 14px;
  color: var(--ink);
  background: transparent;
}

button, .btn {
  min-height: 44px;
  min-width: 44px;
  text-transform: uppercase;
  border: 2px solid var(--ink);
  background: var(--stock);
  color: var(--ink);
  padding: 8px 16px;
  font-size: 15px;
  cursor: pointer;
}
button:disabled, .btn:disabled { color: var(--muted-ink); cursor: default; }
.btn-primary { box-shadow: 4px 4px 0 var(--mustard); }
.btn-primary:active { box-shadow: 2px 2px 0 var(--mustard); transform: translate(2px, 2px); }

/* Mustard never appears as text on paper (fails AA); fill/shadow only.
   --tomato itself is also not AA-safe at small sizes; provider names have
   no guaranteed large/bold size here, so they use --tomato-ink too. */
.provider-name { color: var(--tomato-ink); }
.stale-label { color: var(--muted-ink); }

.site-footer {
  margin-top: 32px;
  padding: 16px;
  font-size: 14px;
  color: var(--muted-ink);
  border-top: 2px solid var(--ink);
}

.messages { list-style: none; padding: 0; }
.messages li { padding: 8px 12px; background: var(--sage); border: 1px solid var(--ink); margin-bottom: 8px; }
.error { color: var(--tomato-ink); font-weight: 600; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}

/* Home split layout (Task 9). Below 900px this is a plain stacked block;
   Task 11 adds the JS-driven bottom sheet on top of it. */
.home-layout {
  display: block;
}
.home-map svg { width: 100%; height: auto; display: block; }
.category-shelves { display: flex; flex-wrap: wrap; margin: 12px 0; }
.shelf-tile { text-decoration: none; }
/* home's "Recently recommended" heading and the shelf/category pages'
   equivalent list heading share one size, smaller than the browser
   default h1/h2 so they read as section labels, not hero titles. */
.list-heading { font-size: 22px; }

@media (min-width: 900px) {
  .home-layout {
    display: grid;
    grid-template-columns: 58% 1fr;
    gap: 16px;
    align-items: start;
  }
  /* The map column stays put while the list scrolls past it. top/height
     below are sized off main's own 16px padding, not a measured header
     height (the header itself is not sticky, so it simply scrolls away
     first) -- provisional constants, not cited from a design spec. */
  .home-map {
    position: sticky;
    top: 16px;
    height: calc(100vh - 32px);
    overflow: hidden;
  }
  .home-map svg { width: 100%; height: 100%; }
}

/* House states (Task 11). The renderer draws each house as
   g#h-<pk>.house with one or more polygon.roof (or polygon.roof.flat)
   facets and polygon.wall facets (book/mapping/illustrate.py); state
   classes here only change fill/stroke, never the shapes themselves. */
g.house.is-lit .roof { fill: var(--mustard); }
g.house.is-mine .roof { fill: var(--tomato); }
g.house.is-pending .wall { stroke-dasharray: 3 2; stroke: var(--ink); }
g.house:focus-visible { outline: 3px solid var(--tomato); outline-offset: 2px; }
/* Recommender houses get their own navy roof (walls untouched), distinct
   from lit (mustard) and mine (tomato). Declared after .is-lit so a house
   that is both lit and a recommender still reads as a recommender. */
g.house.is-recommender .roof { fill: var(--ink); }
.recommender-pin { fill: var(--mustard); stroke: var(--ink); stroke-width: 1; }

/* Bottom sheet, mobile only; the >=900px grid column makes these a no-op */
.sheet-handle, #sheet-toggle { display: none; }
/* House panel header (heading + Close button). Flexed only under the mobile
   media query below so >=900px keeps its plain block h2, unchanged. The
   Close button itself stays display:none outside that query too. */
.panel-close { display: none; }
@media (max-width: 899px) {
  .home-list {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    background: var(--paper);
    border-top: 2px solid var(--ink);
    max-height: 90vh;
    overflow-y: auto;
    transition: max-height 0.2s ease;
    z-index: 5;
    /* Bug fix (phone layout, item 2): match the 16px side padding the map
       and its controls get from main's own padding -- without this the
       sheet's search box, chips and provider cards ran edge to edge. */
    padding: 0 16px 16px;
  }
  .home-list.sheet-peek { max-height: 25vh; }
  .home-list.sheet-half { max-height: 55vh; }
  .home-list.sheet-full { max-height: 92vh; }
  .sheet-handle { display: block; width: 40px; height: 4px; background: var(--ink); margin: 8px auto; border-radius: 2px; }
  #sheet-toggle { display: block; margin: 0 auto 8px; }

  /* Bug fix (phone layout, item 1): on the >=900px grid #house-panel is a
     plain block inside the sticky .home-map column and is left alone. Below
     900px that column isn't sticky or fixed, so a panel simply appended
     there could land far enough down the page to be covered by (or itself
     cover) the fixed sheet above -- e.g. under .sheet-peek's 25vh it was
     rendering behind the sheet's opaque background with only its heading
     clear of the sheet's top edge. Pin it as its own floating card between
     16px of the top of the viewport and 16px above the sheet's peek height,
     at a higher z-index than the sheet (5) so it is always fully visible
     and never shares screen space with the shelf chips or provider cards.
     25vh (not the current peek/half/full state) is a deliberate, simple
     choice -- keeping the panel's bottom edge fixed regardless of sheet
     state is what "nothing overlapping" requires even if the sheet is
     later expanded while the panel stays open. */
  #house-panel:not([hidden]) {
    /* sticky, not fixed: the panel's natural place in the flow is right
       after the map/zoom controls, already below the (non-sticky, non-
       fixed) site header -- a fixed position measured from the viewport
       top would need to know the header's height and would overlap it.
       Sticky keeps that natural top on first paint and only clamps to
       16px from the viewport top once scrolled past it (by which point
       the header itself has already scrolled away with it). */
    position: sticky;
    top: 16px;
    z-index: 6;
    /* Caps the panel's own bottom edge above the sheet's peek height (its
       floor, regardless of the sheet's current peek/half/full state) so
       it can never be covered by, or cover, the sheet -- see the
       .home-list padding comment above for the matching 16px gaps. */
    max-height: calc(100vh - 16px - 25vh - 16px);
    overflow-y: auto;
    overflow-x: hidden;
    margin: 0 16px;
  }
  .house-panel-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 8px;
  }
  .panel-close { display: block; flex-shrink: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .home-list { transition: none; }
}

.map-controls { display: flex; gap: 8px; margin: 8px 0; }
.recommenders-note { font-weight: 600; }
.home-map { touch-action: none; }
