/* ===========================================================================
   Booked Wild — /our-work/

   Loaded after services.css and offer.css, which already carry the header,
   grid, type scale, buttons, rule treatment, .sec grounds, .hero, .usp, .band,
   .close and the contact panel. This page reuses all of it.

   What it adds is one idea, expressed twice at different scales: a real website
   shown inside a real browser. The .chrome component is that idea — a title bar
   with the client's own domain in it, and the live screenshot beneath. Twelve of
   them at gallery scale carry "every site we've built"; two of them at feature
   scale, paired with a phone, carry the case studies.

   The feature composition is not new work. It is the treatment already running
   on the homepage for Safari & Beach — desktop frame, phone mock beside it,
   copy column to the right — which is the one Justine asked to see carried
   across every case study. It is lifted here as a named component so both
   projects get it, rather than one project getting it and the rest getting
   cards.
   =========================================================================== */

/* ---- hero ---------------------------------------------------------------- *
   Eyebrow then h1, the same hierarchy as every other page. The h1 is three
   short sentences, and left to itself the browser breaks wherever the measure
   runs out — "Real names. Real / numbers. Posted / methodology." Each sentence
   is wrapped in a span that cannot break internally, so the only break points
   are the gaps between sentences: the line count changes with the viewport but
   a sentence is never split. No hard <br>, so it still reflows.

   The measure is set in ch rather than px so it tracks the clamp. */
.hero h1 { max-width: 17ch; }
.hero h1 span { white-space: nowrap; }

/* ---- hero scrim ---------------------------------------------------------- *
   The ridge photograph is bright right across the top — sky and cloud — and
   pale again in the valley floor at mid-height, which is exactly where the deck
   sits. Measured under the real glyph rects the deck came out at 3.1:1 against
   the shared scrim, so a horizontal wash is layered under the vertical one to
   weight the text column. Both layers use the same scrim colour, so their
   alphas compose cleanly: 1-(1-av)(1-ah). */
.hero__scrim {
  background:
    linear-gradient(90deg,
      rgba(6, 26, 17, 0.52) 0%, rgba(6, 26, 17, 0.38) 54%, rgba(6, 26, 17, 0) 92%),
    linear-gradient(180deg,
      rgba(6, 26, 17, 0.70) 0%, rgba(6, 26, 17, 0.40) 40%,
      rgba(6, 26, 17, 0.54) 68%, rgba(6, 26, 17, 0.92) 100%);
}
@media (max-width: 768px) {
  .hero__scrim {
    background:
      linear-gradient(90deg, rgba(6, 26, 17, 0.50) 0%, rgba(6, 26, 17, 0.44) 100%),
      linear-gradient(180deg, rgba(6, 26, 17, 0.70) 0%, rgba(6, 26, 17, 0.40) 40%,
        rgba(6, 26, 17, 0.54) 68%, rgba(6, 26, 17, 0.92) 100%);
  }
}

/* ---- the hero's ghost button --------------------------------------------- *
   services.css:242 a:hover{color:var(--ink)} at (0,1,1) outranks
   .btn--ghost{color:var(--white)} at (0,1,0), and .btn--ghost:hover changes
   only the background — so the label turns dark ink over a dark photograph.
   Fixed page-scoped, identical to the rule already on the other pages. The
   closing CTA's "Contact us" has the same button over the same kind of dark
   photograph, and was hitting the same bug: measured on hover it computed to
   rgb(12,42,28) over rgba(255,255,255,0.14), near-black on near-black. Its
   sibling .btn--accent was unaffected — that one sets its own hover colour. */
.hero .btn--ghost:hover,
.hero .btn--ghost:focus-visible,
.close .btn--ghost:hover,
.close .btn--ghost:focus-visible {
  background: rgba(255, 255, 255, 0.18);
  border-color: #FFFFFF;
  color: var(--white);
}

/* ---- highlights stripe --------------------------------------------------- *
   Four figures on white between the hero and the gallery, per the approved
   mock-up. It reflows 4 -> 2 -> 1 rather than holding four columns down to a
   phone, where "Independent travel and hospitality" in a 90px track would break
   to one word per line. */
.stripe { background: var(--white); border-bottom: 1px solid var(--line); padding: 34px var(--pad); }
.stripe__grid {
  max-width: var(--max);
  margin: 0 auto;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 34px;
  list-style: none;
  padding: 0;
}
.stripe__fig {
  font-family: 'Schibsted Grotesk', sans-serif;
  font-size: clamp(24px, 2vw, 34px);
  line-height: 1;
  letter-spacing: -0.03em;
  font-weight: 800;
  color: var(--ink);
  margin: 0 0 8px;
}
.stripe__cap {
  font-family: 'Karla', sans-serif;
  font-size: 16px;
  line-height: 1.45;
  color: var(--body);
  margin: 0;
}

/* ---- the browser frame --------------------------------------------------- *
   Shared by the gallery cards and the case-study features, so a site looks the
   same whatever scale it is shown at. The title bar carries the client's real
   domain, which is what makes the screenshot beneath read as a live site rather
   than a mockup. */
.chrome {
  border-radius: 14px;
  overflow: hidden;
  background: var(--ink-2);
  box-shadow: 0 26px 60px rgba(0, 0, 0, 0.38);
}
.chrome__bar {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 15px;
  background: var(--tint);
}
.chrome__dots { display: flex; gap: 6px; flex: none; }
.chrome__dots span { width: 9px; height: 9px; border-radius: 50%; background: #C9D3C3; }
.chrome__url {
  font-family: 'Karla', sans-serif;
  font-size: 12.5px;
  line-height: 1;
  color: #4A5F50;
  background: var(--white);
  border-radius: 999px;
  padding: 6px 13px;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
/* The shot is absolutely positioned so the box takes its height from the ratio
   rather than from the file — height:100% on the img alone would fall back to
   the image's own aspect ratio in an auto-height parent.

   The frame's ratio has to be at least as wide as the screenshots, or cover
   scales them to fill the height and throws the sides away. At 16/10 it did
   exactly that: seven of the twelve captures are 1400x677 (2.068) and lost
   22.6% of their width, 11.3% off each edge, which is where a website keeps its
   logo and the ends of its nav. Safari & Beach (1400x640) lost 26.9%. The three
   that looked right — Kotisome, Villa Sarva, Snow & Pine — are 1200x750, which
   is exactly 16/10, so they lost nothing. That was the whole difference.

   At 1400/677 the seven majority captures fit to the pixel, Safari & Beach
   loses 5.5% of its width, and the 1200x750 trio give up 22.6% of their height
   from the bottom instead — which is what a browser viewport does anyway. */
.chrome__shot { position: relative; background: var(--white); overflow: hidden; }
.chrome__shot img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: 50% 0;
  display: block;
}

/* ---- the phone beside it ------------------------------------------------- */
.phone {
  width: 184px;
  flex: none;
  border-radius: 26px;
  border: 8px solid var(--ink-2);
  overflow: hidden;
  background: var(--white);
  box-shadow: 0 24px 50px rgba(0, 0, 0, 0.40);
}
.phone__shot { position: relative; aspect-ratio: 13 / 20; overflow: hidden; }
.phone__shot img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: 50% 0;
  display: block;
}

/* ---- the gallery --------------------------------------------------------- */
.gal__head {
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
  gap: 60px;
  align-items: end;
  margin-bottom: 40px;
}
.gal__head h2 { margin: 0; }
.gal__head .lede { margin: 0; max-width: 42ch; }

.gal__filters {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin-bottom: 32px;
  padding: 0;
  list-style: none;
}
.gal__filter {
  font-family: 'Karla', sans-serif;
  font-size: 15.5px;
  font-weight: 500;
  line-height: 1;
  padding: 11px 18px;
  border-radius: 999px;
  cursor: pointer;
  border: 1px solid rgba(159, 220, 169, 0.34);
  background: transparent;
  color: rgba(242, 246, 238, 0.82);
  transition: background .2s ease, color .2s ease, border-color .2s ease;
}
.gal__filter:hover { border-color: var(--accent-mid); color: var(--white); }
.gal__filter:focus-visible { outline: 3px solid var(--accent-soft); outline-offset: 2px; }
.gal__filter[aria-pressed="true"] {
  background: var(--accent-soft);
  border-color: var(--accent-soft);
  color: var(--ink);
  font-weight: 600;
}
/* Without JS the filters cannot do anything, so they are not offered at all
   rather than sitting there inert. services.js adds .bw-js to <html>. */
html:not(.bw-js) .gal__filters { display: none; }

.gal__grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 26px;
  list-style: none;
  padding: 0;
  margin: 0;
}
.gal__card { display: flex; }
.gal__card[hidden] { display: none; }

/* One link per card: the whole card is the target, so there is a single tab
   stop and no nested interactive elements. */
.gal__link {
  display: flex;
  flex-direction: column;
  gap: 16px;
  width: 100%;
  background: var(--card);
  border-radius: 20px;
  padding: 18px;
  text-decoration: none;
  color: inherit;
  transition: background .22s ease, transform .22s ease;
}
.gal__link:hover { background: #164430; transform: translateY(-3px); }
.gal__link:focus-visible { outline: 3px solid var(--accent-soft); outline-offset: 3px; }
.gal__link:hover .chrome__shot img { transform: scale(1.03); }
/* A real 1400px-wide browser viewport, which is what these screenshots are.
   The frame used to be 16/10; see the note on .chrome__shot img. */
.gal__link .chrome__shot { aspect-ratio: 1400 / 677; }
.gal__link .chrome__shot img { transition: transform .5s ease; }

.gal__meta { display: flex; align-items: baseline; justify-content: space-between; gap: 14px; }
.gal__name {
  font-family: 'Karla', sans-serif;
  font-size: 16.5px;
  font-weight: 600;
  color: var(--white);
  margin: 0;
}
.gal__place {
  font-family: 'Karla', sans-serif;
  font-size: 14px;
  color: rgba(242, 246, 238, 0.58);
  margin: 0;
  text-align: right;
}
.gal__type {
  font-family: 'Karla', sans-serif;
  font-size: 11.5px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  font-weight: 700;
  color: var(--accent-soft);
  margin: 0;
}
.gal__note {
  font-family: 'Karla', sans-serif;
  font-size: 15px;
  line-height: 1.5;
  color: rgba(242, 246, 238, 0.76);
  margin: 0;
}
.gal__go {
  font-family: 'Karla', sans-serif;
  font-size: 15px;
  font-weight: 600;
  color: var(--white);
  margin: 0;
  display: inline-flex;
  align-items: center;
  gap: 8px;
}
.gal__go::after { content: "\2197"; font-size: 15px; }
.gal__link:hover .gal__go { color: var(--accent-soft); }

/* The overlay is the desktop hover flourish. It carries nothing that is not
   also in the card body, so a device that cannot hover loses a nicety and no
   information — see the (hover: none) branch below. */
.gal__ov {
  position: absolute;
  inset: 0;
  z-index: 3;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  gap: 10px;
  padding: 20px;
  background: linear-gradient(180deg,
    rgba(6, 26, 17, 0.10) 0%, rgba(6, 26, 17, 0.86) 62%, rgba(6, 26, 17, 0.95) 100%);
  opacity: 0;
  transition: opacity .24s ease;
}
.gal__link:hover .gal__ov,
.gal__link:focus-visible .gal__ov { opacity: 1; }
.gal__ov .gal__note { color: #FFFFFF; }

/* Pointer-coarse and every narrow viewport: no overlay at all. The body already
   holds the type, the note and the link, so nothing is lost. */
@media (hover: none), (max-width: 1024px) {
  .gal__ov { display: none; }
  .gal__link:hover { transform: none; }
}
/* Hover-capable and wide: the note lives in the overlay, so the body stays as
   quiet as the mock-up has it. */
@media (hover: hover) and (min-width: 1025px) {
  .gal__body--static { display: none; }
}
@media (hover: none), (max-width: 1024px) {
  .gal__body--static { display: flex; flex-direction: column; gap: 10px; }
}

.gal__count {
  font-family: 'Karla', sans-serif;
  font-size: 15px;
  color: rgba(242, 246, 238, 0.6);
  margin: 26px 0 0;
}

/* ---- the gallery/case-study boundary ------------------------------------- *
   .sec carries 120px top and bottom, so every boundary on this site is 240px.
   That reads as a break where the ground colour changes across it. The gallery
   and the case studies are both sec--dark, so those 240px became one unbroken
   run of dark green with nothing in it — the page looked like it had lost a
   section. Where two dark sections abut, the boundary now carries one section's
   worth of padding rather than two. Conditional on the adjacency, so a colour
   change anywhere keeps the full 240px. Same treatment already used for
   abutting cream sections on /services/. */
.sec--dark + .sec--dark { padding-top: 56px; }
.sec--dark:has(+ .sec--dark) { padding-bottom: 56px; }

/* ---- case-study feature -------------------------------------------------- *
   The homepage composition, named. Media left, copy right; the media is a
   desktop browser frame with a phone stood at its foot. */
.feat {
  background: var(--card);
  border-radius: 24px;
  padding: 40px;
  display: grid;
  grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr);
  gap: 48px;
  align-items: center;
}
.feat + .feat { margin-top: 26px; }
.feat__mocks { display: flex; align-items: flex-end; gap: 24px; min-width: 0; }
.feat__mocks .chrome { flex: 1; min-width: 0; }
.feat__mocks .chrome__shot { aspect-ratio: 11 / 5; }

.feat__num {
  font-family: 'Karla', sans-serif;
  font-size: 13px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  font-weight: 600;
  color: var(--accent-soft);
  margin: 0 0 14px;
}
.feat__eyebrow {
  font-family: 'Karla', sans-serif;
  font-size: 13px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  font-weight: 700;
  color: rgba(242, 246, 238, 0.62);
  margin: 0;
}
.feat__ctx {
  font-family: 'Karla', sans-serif;
  font-size: 17.5px;
  line-height: 1.55;
  color: rgba(242, 246, 238, 0.78);
  margin: 14px 0 0;
}
/* the measurable result, which is the point of the entry */
.feat__result {
  font-family: 'Schibsted Grotesk', sans-serif;
  font-size: clamp(22px, 2.1vw, 34px);
  line-height: 1.14;
  letter-spacing: -0.025em;
  font-weight: 700;
  color: var(--white);
  margin: 20px 0 0;
  max-width: 26ch;
}
.feat__actions { display: flex; gap: 12px; align-items: center; flex-wrap: wrap; margin-top: 28px; }
.feat__live {
  font-family: 'Karla', sans-serif;
  font-size: 13px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  font-weight: 700;
  color: var(--ink);
  background: var(--accent-mid);
  padding: 9px 16px;
  border-radius: 999px;
}

/* ---- responsive ---------------------------------------------------------- */
@media (max-width: 1200px) {
  .gal__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 1024px) {
  .stripe__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 28px 30px; }
  /* copy under the composition — the screenshots are the point here */
  .feat { grid-template-columns: minmax(0, 1fr); gap: 34px; padding: 32px; }
  /* Both clamps bottom out from here down — a 22px result against a 17.5px
     sentence — so the number stopped reading as the point of the entry. The
     contrast is reopened by hand rather than left to the clamps. */
  .feat__ctx { font-size: 16.5px; }
  .feat__result { font-size: 27px; line-height: 1.14; margin-top: 22px; }
  .gal__head { grid-template-columns: minmax(0, 1fr); gap: 18px; align-items: start; }
  .gal__head .lede { max-width: 56ch; }
  .feat__result { max-width: none; }
}
@media (max-width: 900px) {
  /* A fixed 184px phone beside the desktop frame left it about 90px of width at
     this size. They stack instead of racing for the same row, which is what the
     homepage does at the same breakpoint. */
  .feat__mocks { flex-direction: column; align-items: stretch; gap: 20px; }
  .feat__mocks .phone { width: 168px; align-self: flex-start; }
}
@media (hover: none), (max-width: 1024px) {
  /* 44px minimum target once the pointer is likely to be a finger */
  .gal__filter { padding: 14px 18px; }
}
@media (max-width: 768px) {
  .stripe { padding: 28px var(--pad); }
  .stripe__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 26px 24px; }
  .gal__grid { grid-template-columns: minmax(0, 1fr); gap: 20px; }
  .feat { padding: 24px; gap: 28px; }
  .feat + .feat { margin-top: 20px; }
  .gal__filters { gap: 8px; margin-bottom: 26px; }
  .gal__filter { font-size: 14.5px; padding: 14px 16px; }
}
@media (max-width: 560px) {
  .stripe__grid { grid-template-columns: minmax(0, 1fr); gap: 22px; }
  .hero h1 { max-width: none; }
  .feat { padding: 18px; border-radius: 18px; }
  /* The result is the point of the entry, but both clamps bottom out down here
     — 22px against 17.5px — so the number ran into the sentence above it as one
     block. The gap is reopened by hand rather than left to the clamps. */
  .feat__ctx { font-size: 16px; }
  .feat__result { font-size: 25px; line-height: 1.16; margin-top: 22px; }
  .feat__mocks { gap: 16px; }
  .feat__mocks .phone { width: 148px; border-width: 6px; border-radius: 22px; }
  .gal__link { padding: 14px; border-radius: 16px; }
  /* a full-width tap target rather than a 15px inline link */
  .gal__go { font-size: 15.5px; }
}

@media (prefers-reduced-motion: reduce) {
  .gal__link, .gal__link:hover, .chrome__shot img { transition: none; transform: none; }
}

/* ---- case-study action on the featured cards -----------------------------
   A third action beside the Live badge and the live-site button. The row
   already wraps, so it only needs the ghost treatment for this dark ground
   plus a floor on the touch target. */
.feat__cs { color: var(--white); border-color: rgba(242, 246, 238, 0.42); }
.feat__cs:hover,
.feat__cs:focus-visible { color: var(--white); background: var(--accent); border-color: var(--accent); }
@media (max-width: 560px) {
  .feat__actions { gap: 12px; }
  .feat__actions .btn { width: 100%; text-align: center; justify-content: center; }
}
