/* ==============================
   HOME PAGE
   for History Habitat
   Loaded only by index.htm, after page.css
   ============================== */

/*
/   HERO SWEEP - two pixel-aligned stills, a divider sweeping slowly between
/   them, which visitors with a mouse or trackpad can also drag (driven by
/   assets/js/hero-sweep.js). Heading, text and actions below.
*/
.hh-sweep-wrap {
  max-width: var(--w-wide);
  margin: 16px auto 0 auto;
}
.hh-sweep {
  position: relative;
  width: 100%;
  aspect-ratio: 1360 / 650;
  /* Never taller than the visible screen height minus 160 px, so that the heading shows
     when the page opens on short landscape screens (laptops at 125-150 % scaling,
     1366 x 768, tablets held sideways): the 74 px above the image, the gap and the
     heading's line (66 px), and 20 px of room. The width stays; the stills are cut at
     the top and bottom alike (see below). Never below 240 px: phones held sideways open
     on the whole image, without the heading. svh is the height with the browser's bars
     showing; browsers from before 2022 ignore that line and keep the vh one. (Owner,
     2026-09-30, tried in 0tests/hero-height-sketch.htm; checked by
     .tools/hero-height-test.mjs.) */
  max-height: max(240px, calc(100vh - 160px));
  max-height: max(240px, calc(100svh - 160px));
  overflow: hidden;
  background: var(--clr-bg);    /* never a light box while the stills load */
}
/* Fade-in: the whole box (maps, line, label, button, shadow) stays invisible until both
   stills are decoded, then hero-sweep.js adds .hh-ready. The class on <html> is set by a
   one-line script in the head, so without JavaScript the stills simply show. Failsafe:
   if hero-sweep.js never runs, the box appears after 8 s anyway. */
.hh-sweep-js .hh-sweep {
  opacity: 0;
  transition: opacity .6s ease;
}
.hh-sweep-js .hh-sweep:not(.hh-ready) { animation: hh-sweep-failsafe 0s 8s forwards; }
.hh-sweep-js .hh-sweep.hh-ready { opacity: 1; }
@keyframes hh-sweep-failsafe { to { opacity: 1; } }
/* Both stills share one box and one crop, so they stay pixel-aligned at any size. Where
   the box is flatter than the stills (the height limit above), cover's default position,
   the centre, cuts the top and bottom alike: the top alone would take the river on the
   right and the Commission's Sackville Street and Carlisle Bridge (owner, 2026-09-30) */
.hh-sweep img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
/* The top still, left of the divider. Its frame is shifted left so the frame's right
   edge sits at the divider, and the image inside is shifted back by the same amount:
   the map stays put, only the edge travels. Both are pure transforms, so the graphics
   card moves ready-made layers and nothing is redrawn (animating clip-path repainted
   the whole image every frame). */
.hh-sweep-clip {
  position: absolute;
  inset: 0;
  overflow: hidden;
  will-change: transform;
}
.hh-sweep-clip img { will-change: transform; }

/* Full-width carrier: translateX(P px) puts its left edge, the line, at the divider */
.hh-sweep-line {
  position: absolute;
  inset: 0;
  pointer-events: none;
  will-change: transform;
}
/* The app's divider line (mapa css/core.css #split-divider::before, values from
   all_vars.css): 3px white, a crisp 1px dark ring, no blur. left is -floor(3 / 2),
   a whole pixel, so the line stays crisp at DPR 1 too. */
.hh-sweep-line::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: -1px;
  width: 3px;
  background: #ffffff;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, var(--hh-ring-alpha));   /* brighter on the line and while dragged, below */
}

.hh-sweep-label {
  position: absolute;
  left: 16px;
  top: 16px;
  padding: 4px 12px;
  background: rgba(35, 50, 60, .82);
  color: #f0f0f0;
  font-size: 15px;
  letter-spacing: .02em;
}
/* While the line can be dragged, the label lets the pointer through, so the line can be
   grabbed where it passes under it */
.hh-draggable .hh-sweep-label { pointer-events: none; }

/* Lucide icons, inlined as SVG (lucide.dev, ISC licence; the app carries the library in
   mapa icons/lucide.js): on the buttons on the image and on the two buttons below it.
   Lucide's own drawing attributes: a 24-unit box, round 2-unit strokes, no fill, in the
   text colour. */
.hh-icon {
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Two square buttons side by side in the bottom-right corner (owner, 2026-09-28): pause/
   play, and in the corner the link to what the image shows, the split view in the app
   without panels, in a new tab. Its icon is the familiar "open in a new tab" (Lucide
   external-link, the drawing of the site's brand-externalLink-icon). Square like the
   label, darker on hover. All three icons are line drawings of the same weight: filled,
   pause and play looked heavier (owner). The row lets the pointer through its gap,
   where the line can still be grabbed. */
.hh-sweep-controls {
  position: absolute;
  right: 12px;
  bottom: 12px;
  display: flex;
  gap: 6px;
  pointer-events: none;
}
.hh-sweep-controls > * { pointer-events: auto; }
.hh-sweep-pause,
.hh-sweep-open {
  width: 36px;
  height: 36px;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: rgba(35, 50, 60, .75);
  color: #ffffff;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}
.hh-sweep-pause[hidden] { display: none; }   /* reduced motion: no pause button */
.hh-sweep-pause:hover,
.hh-sweep-open:hover { background: rgba(35, 50, 60, .95); }
.hh-sweep-pause:focus-visible,
.hh-sweep-open:focus-visible { outline: 2px solid #f0f0f0; outline-offset: 2px; }
.hh-sweep-controls .hh-icon { width: 18px; height: 18px; }
/* The pause button holds both icons; hero-sweep.js puts .hh-paused on it while paused */
.hh-sweep-pause.hh-paused .hh-i-pause,
.hh-sweep-pause:not(.hh-paused) .hh-i-play { display: none; }

/*
/   DRAGGING THE DIVIDER (owner's proposal, 2026-09-27). Only where the main input is a
/   mouse or trackpad: hero-sweep.js then puts .hh-draggable on the box. Phones and
/   tablets keep the plain sweep, with no handle and no strip: on the owner's phone
/   grabbing the line stayed unreliable after two rounds of fixes (2026-09-27), and a hero
/   that is harder to use than the app would make the app look flawed. The handle and the
/   grab strip copy the app's (mapa css/core.css #split-divider and .split-handle, values
/   from all_vars.css), so visitors meet the same control on the site and in the app.
/   Worked out in 0tests/hero-drag-sketch.htm; see CLAUDE.md, "Draggable divider".
*/
.hh-sweep {
  --hh-hit-mouse: 29px;     /* as wide as the handle, 27 px, with its 1 px ring (the app's) */
  --hh-hit-touch: 36px;     /* as wide as the pause button on touch screens (owner, 2026-09-27) */
  --hh-hit: var(--hh-hit-mouse);
  --hh-ring-alpha: .45;     /* the dark ring round line and handle */
  --hh-grip-alpha: .85;     /* the chevrons */
  --hh-handle-gap: 12px;    /* the handle's ring above the buttons */
}
@media (any-pointer: coarse) {
  .hh-sweep { --hh-hit: var(--hh-hit-touch); }   /* touch laptops */
}

/* While the line can be dragged: no text selection, long-press callout, image dragging
   or tap flash anywhere in the hero. A careful, slow press on the line is a long press,
   which on the owner's phone selected the whole box and marked the label (2026-09-27). */
.hh-sweep.hh-draggable {
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
  -webkit-tap-highlight-color: transparent;
}
.hh-draggable img { -webkit-user-drag: none; }
/* No dragging: no strip, and with it no handle */
.hh-sweep:not(.hh-draggable) .hh-sweep-grab { display: none; }

/* Brighter while the pointer is on the line and while it is dragged, as in the app.
   Set on the line's carrier, so the line and the handle change together. */
@media (hover: hover) {
  .hh-sweep-line:has(.hh-sweep-grab:hover) { --hh-ring-alpha: .7; --hh-grip-alpha: 1; }
}
.hh-sweep-line.hh-dragging { --hh-ring-alpha: .7; --hh-grip-alpha: 1; }

/* The grab strip: the whole height of the line, centred on it; nothing drawn. The line's
   carrier lets pointers through, the strip catches them.
   touch-action: none, as on the app's divider: every movement of a finger on the strip is
   a drag. It let up-down swipes through to the page until the owner's phone test
   (2026-09-27): the phone then decided at the finger's first movement between scroll and
   drag, so a drag that began slightly up or down became a scroll and lost the line. The
   cost: a scroll that starts on the strip does not scroll the page. */
.hh-sweep-grab {
  position: absolute;
  top: 0;
  bottom: 0;
  left: calc(var(--hh-hit) / -2);
  width: var(--hh-hit);
  pointer-events: auto;
  cursor: ew-resize;
  touch-action: none;
}
/* The browser takes the cursor from the element that holds the drag, the strip, so a
   drag begun on the handle shows the closed hand through a class (as in the app) */
.hh-sweep-grab.hh-drag-handle { cursor: grabbing; }

/* The handle: a white circle on the line, the line running into it. Its centre is the
   line's centre (the line runs from -1 to +2 px of the divider). Its ring sits 12 px
   above the buttons, raised from 6 px at the owner's suggestion (2026-09-28); 12 is
   twice the gap between the two buttons, so the handle does not read as a third button:
   12 px inset + 36 px button + 12 px + 1 px ring = 61 px from the bottom. With the 30 px
   end margin it stands straight above the corner button at the right end. */
.hh-sweep-handle {
  position: absolute;
  left: calc(var(--hh-hit) / 2 - 13px);
  bottom: calc(12px + 36px + var(--hh-handle-gap) + 1px);
  width: 27px;
  height: 27px;
  border-radius: 50%;
  background: #ffffff;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: grab;
}
/* The ring, painted under the line, so the line runs into the circle with no dark seam
   (the app's "bead on a string"). z-index -1 sends it below the line only because nothing
   between here and the line's carrier forms a stacking context: no transform, opacity or
   z-index on the handle or the strip. */
.hh-sweep-handle::before {
  content: "";
  position: absolute;
  inset: -1px;
  border: 1px solid rgba(0, 0, 0, var(--hh-ring-alpha));
  border-radius: inherit;
  z-index: -1;
}
/* Two chevrons, the app's grip: an 18 px box, stroke 1 on a 14-unit drawing, spread
   1.3 units apart (units of the drawing, not screen pixels) */
.hh-sweep-handle svg {
  width: 18px;
  height: 18px;
  fill: none;
  stroke: #67615b;
  stroke-width: 1;
  stroke-linecap: butt;
  stroke-linejoin: miter;
  opacity: var(--hh-grip-alpha);
  transition: opacity 150ms ease;
}
.hh-sweep-handle .chev-l { transform: translateX(-1.3px); }
.hh-sweep-handle .chev-r { transform: translateX(1.3px); }

/* Narrow screens: a taller crop of the same view instead of a flat strip */
@media (max-width: 700px) {
  .hh-sweep { aspect-ratio: 4 / 3; }
}

/* Text and actions below the animation: heading, sentence, then the actions in a row
   beneath; from 1200 px text left and actions stacked right (see below). No side
   padding: the text starts on the image's left edge at every width. */
.hh-intro-row {
  max-width: var(--w-wide);
  margin: 1.6rem auto 0 auto;   /* the gap below is the next section's (PAGE LAYOUT) */
}
/* The heading is not reading text: it may run wider than the prose column, so it stays
   on one line on desktop. Its size, weight and font are every heading's (PAGE LAYOUT) */
/* .hh-nowrap is in page.css since 2026-10-05: every page uses it */
.hh-intro-text .hh-feature-sub {
  max-width: var(--w-prose);
  margin: 0;
}

/* The actions: equal height, side by side, wrapping when there is no room */
.hh-intro-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: stretch;
  gap: 12px 16px;
  margin-top: 1.4rem;
}
/* Both buttons one line high, an icon before the text; the app link keeps the teal
   outline so the gold stays with the one action that brings in business */
.hh-intro-actions .hh-btn {
  display: flex;
  align-items: center;
  gap: 12px;
  font-weight: 500;
}
/* Their Lucide icons (layout-grid on the teal one, mail on the gold one), drawn at 20 px
   in a 22 px wide box, so stacked button texts start in line */
.hh-intro-actions .hh-icon { width: 22px; height: 20px; }
/* The teal button's new-tab mark after its label: set aside (owner, 2026-09-28: it looks
   odd, and "Try ... in the app" already says the visitor is leaving the page), kept as a
   possible future option; to show it, take out "display: none". It is the site's own
   mark (page.css brand-externalLink-icon, 0.8 of the text size), but in the button's
   colour rather than the light grey it has after text links, so it belongs to the
   button and turns dark with the text on hover. It stays with "app" if the label wraps. */
.hh-btn .brand-externalLink-icon { display: none; background: currentColor; }

/* Wide screens: text left, the actions stacked in a column right, the column's right
   edge on the image's right edge, so both edges of the image have something under them */
@media (min-width: 1200px) {
  .hh-intro-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 64px;
  }
  .hh-intro-actions {
    flex: 0 0 auto;
    flex-direction: column;   /* stretch gives the buttons the width of the widest */
    margin-top: 0;
  }
}
/* Where the buttons no longer fit side by side: stacked, both as wide as the wider one,
   on phones too (owner, 2026-09-30; until then full width from 768 px down) */
@media (max-width: 830px) {
  .hh-intro-actions { flex-direction: column; width: fit-content; max-width: 100%; }
}

/*
/   FEATURE - a video with its heading, text and buttons beside it.
/   Wide: video left (max 960), heading + body in a column right.
/   Narrow: heading, then video, then body - one markup order, two layouts.
/   Was the hero until 2026-09-23; now unused on the home page, kept for the
/   planned introduction/tutorial page.
*/
.hh-feature {
  display: grid;
  grid-template-columns: minmax(0, 960px) minmax(300px, 1fr);
  grid-template-rows: auto 1fr;
  grid-template-areas:
    "video head"
    "video body";
  column-gap: 40px;
  max-width: var(--w-wide);
  margin: 0 auto;
  padding-top: 24px;
}
.hh-feature-video { grid-area: video; }
.hh-feature-head  { grid-area: head; }
.hh-feature-body  { grid-area: body; }

.cb-page .hh-feature-head {
  font-size: 34px;
  font-weight: 500;
  line-height: 1.2;
  margin: 0 0 0.8rem 0;
}
.hh-feature-sub {
  font-size: 18px;
  color: #e8e8e8;
  margin: 0 0 1.2rem 0;
}

@media (max-width: 1100px) {
  .hh-feature {
    grid-template-columns: minmax(0, 960px);
    grid-template-rows: auto;
    grid-template-areas:
      "head"
      "video"
      "body";
    justify-content: center;
  }
  .hh-feature-body { max-width: var(--w-prose); margin-top: 1.2rem; }
}

/*
/   VIDEO
/   1920x1080 encodes shown at no more than 960 CSS px: one video pixel per
/   screen pixel on a DPR 2 display, an exact halving on a DPR 1 display.
/   The padding-top fallback keeps older browsers from collapsing the box.
*/
.hh-video-frame {
  position: relative;
  width: 100%;
  max-width: 960px;
  background: #17232b;
  overflow: hidden;
}
.hh-video-frame::before {
  content: "";
  display: block;
  padding-top: 56.25%;   /* 16:9 */
}
.hh-video-frame video {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  display: block;
}
.hh-video-caption {
  font-size: 13px;
  color: var(--clr-muted);
  margin-top: 8px;
  margin-bottom: 0;
}

/*
/   CALLS TO ACTION
*/
.hh-cta {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 12px;
  margin: 0 0 1rem 0;
}
.hh-btn {
  display: inline-block;
  padding: 12px 26px;
  font-size: 17px;
  text-decoration: none;
  border: 1px solid transparent;
  transition: background-color .2s ease, color .2s ease;
}
.hh-btn-primary {
  background-color: var(--clr-accent);
  color: #23323c;
  font-weight: 500;
}
.hh-btn-primary:hover {
  background-color: #e6dc9b;
  text-decoration: none;
}
.hh-btn-secondary {
  border-color: var(--clr-link);
  color: var(--clr-link);
}
.hh-btn-secondary:hover {
  background-color: var(--clr-link);
  color: #23323c;
  text-decoration: none;
}
.hh-cta-note {
  font-size: 14px;
  color: var(--clr-muted);
  margin-top: 0.2rem;
}

/*
/   PAGE LAYOUT - one set of rules for every section after the hero (owner, 2026-09-30;
/   worked out in 0tests/layout-sketch.htm, see CLAUDE.md, "Open", item 5; checked by
/   .tools/layout-rules-test.mjs):
/   - every section reaches both edges of the 1360 px box; text keeps its reading width
/     (720 px), and an image or a second block of text stands beside it;
/   - one gap between sections, 96 px (64 on phones), larger than any gap inside one
/     (heading to text 12 px, paragraph to paragraph 1em); no lines between sections
/     ("line only adds noise", owner);
/   - one heading style for every heading, the hero's included: 28 px at weight 500 (24 on
/     phones), in Roboto like the text (W3.CSS gives headings "Segoe UI", which is Arial
/     on phones and Macs);
/   - one body size, 18 px (17 on phones);
/   - every two-column section switches at 1200 px.
*/
.cb-page { --hh-gap: 96px; }
.hh-sec { margin-top: var(--hh-gap); }
/* The first section of a page without a hero (credits.htm): below the navbar, not a gap */
.hh-sec.hh-sec-first { margin-top: 40px; }
#start { padding-bottom: calc(var(--hh-gap) / 2); }

.cb-page h1,
.cb-page .hh-intro-text h1 {
  font-family: 'Roboto', sans-serif;
  font-size: 28px;
  font-weight: 500;
  line-height: 1.25;
  margin: 0 0 12px 0;
}

/* Inside a section: text at its reading width, paragraphs 1em apart, nothing after the
   last one (the gap to the next section is the section's own) */
.hh-sec-text,
.hh-pns-text p { max-width: var(--w-prose); }
.hh-sec p,
.hh-sec .hh-clients { margin: 0 0 1em 0; }
.hh-sec-text > :last-child,
.hh-pns-text > :last-child,
.hh-sec > p:last-child { margin-bottom: 0; }

/*
/   POINT-AND-SEE - six maps from the app's list, at most at the app's size, 280 x 158 CSS
/   px, never enlarged (the files are the 200 % grabs). Under 1200 px: text above, the maps
/   below, three across while three fit at 240 px, then two, then one (container queries
/   on the section's own width; their numbers follow --pns-min, since a query cannot read a
/   variable; browsers without them, before 2023, show one column). From 1200 px: text
/   left, maps right; the maps stay at 280 while the text column has 376 px (the width the
/   owner found good at 1320) and shrink, down to 240, before the text does.
*/
.hh-pns {
  --pns-w: 280px;
  --pns-min: 240px;
  --pns-text: 376px;
  container: hh-pns / inline-size;
}
.hh-pns-grid {
  display: grid;
  grid-template-columns: minmax(0, var(--pns-w));
  gap: 16px;
  margin-top: 1em;
}
@container hh-pns (min-width: 496px) {   /* two at 240 px and one gap */
  .hh-pns-grid { grid-template-columns: repeat(2, minmax(0, var(--pns-w))); }
}
@container hh-pns (min-width: 752px) {   /* three at 240 px and two gaps */
  .hh-pns-grid { grid-template-columns: repeat(3, minmax(0, var(--pns-w))); }
}
.hh-pns-grid img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 280 / 158;
  box-shadow: 0 4px 10px 0 rgba(0,0,0,0.2), 0 4px 20px 0 rgba(0,0,0,0.19);
}
@media (min-width: 1200px) {
  .hh-pns {
    display: flex;
    align-items: flex-start;
    gap: 40px;
  }
  /* The text grows into any room left. When room runs short the maps give way first (a
     shrink factor a thousand times the text's), down to their smallest width; only then
     does the text. Not a tiny shrink factor on the text instead: a factor below 1 takes
     only that fraction of the missing room, and the maps would overflow the page. */
  .hh-pns-text {
    flex: 1 1 var(--pns-text);
    min-width: 0;
  }
  .hh-pns-grid {
    flex: 0 1000 calc(3 * var(--pns-w) + 32px);
    min-width: calc(3 * var(--pns-min) + 32px);
    margin-top: 0;
  }
}

/*
/   MISSION - James Malton's print of College Green in 1793 beside the text from 1200 px,
/   below it on narrower screens; the caption in the text colour, a little smaller
/   (14 px, owner, 2026-09-30)
*/
.hh-sec-fig {
  margin: 1em 0 0 0;
  max-width: var(--w-prose);
}
.hh-sec-fig img {
  display: block;
  width: 100%;
  height: auto;
  box-shadow: 0 4px 10px 0 rgba(0,0,0,0.2), 0 4px 20px 0 rgba(0,0,0,0.19);
}
.hh-sec-fig figcaption {
  margin-top: 10px;
  font-size: 14px;
  line-height: 1.5;
  color: rgba(240, 240, 240, .85);
}
@media (min-width: 1200px) {
  .hh-split {
    display: flex;
    align-items: flex-start;
    gap: 40px;
  }
  .hh-split > .hh-sec-text { flex: 0 1 var(--w-prose); min-width: 0; }
  .hh-split > .hh-sec-fig { flex: 1 1 0; min-width: 0; max-width: none; margin-top: 0; }
}

/*
/   TRACK RECORD and CONTACT - side by side from 1200 px (owner, 2026-09-30); the pair
/   then takes the section gap
*/
.hh-clients {
  list-style: none;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 8px 28px;
}
@media (min-width: 1200px) {
  .hh-pair {
    display: flex;
    gap: 40px;
    margin-top: var(--hh-gap);
  }
  .hh-pair > .hh-sec {
    flex: 1 1 0;
    min-width: 0;
    margin-top: 0;
  }
}

/*
/   CREDITS
*/
.hh-credits {
  font-size: 12px;
  color: var(--clr-muted);
  line-height: 1.6;
}
.hh-credits a {
  color: var(--clr-muted);
}

/* --- Responsive adjustments --- */
@media (max-width: 768px) {
  .cb-page { --hh-gap: 64px; font-size: 17px; }   /* one body size: 17 px on phones */
  .cb-page h1,
  .cb-page .hh-intro-text h1 { font-size: 24px; }
  .cb-page .hh-feature-head { font-size: 28px; }
  .hh-feature-sub { font-size: 17px; }
  .hh-btn { display: block; padding: 14px 20px; }
  /* Full width only for the tutorial page's buttons; the hero's keep their width (owner,
     2026-09-30) */
  .hh-cta .hh-btn { width: 100%; }
  .hh-cta { gap: 10px; }
}
