/* =====================================================================
   Sharpening Plus: native adapters

   Hand-written. Everything WordPress needs that the work copy never had:
   where core's block markup differs from the work copy's, the mapping
   lives here, loaded after every ported sheet. The ported sheets stay
   byte-for-byte diffable against the snapshot; a fix made in one of them
   would be reverted by the next regenerate.

   A  Page shell     the wrappers core adds around the template
   B  Blocks         core block markup inside the ported sections
   C  The form       Contact Form 7's markup around the question form
   D  Route credit   the map-data credit the calendar script adds
   E  Empty states   the rail with no visits, and the test calendar note
   F  Day details    hours and places in the days, month tabs, rail entries
   G  Booking        days off, the booking request, the About photo strip
   H  Masthead width the split masthead from 920px, with the pages
   ===================================================================== */


/* ---------------------------------------------------------------------
   A  Page shell
   The masthead is sticky, and a sticky box only travels inside its
   parent. The header template part wraps it in a div exactly as tall as
   the bar, so that div steps out of the box tree and the masthead's
   parent is the page again, as it is in the work copy.
   --------------------------------------------------------------------- */
.wp-site-blocks { padding: 0; }
.sp-masthead-part { display: contents; }

/* The work copy's schedule buttons scroll with a 72px allowance for the
   sticky bar. The tagline's is a link here, and the browser's own jump
   to the anchor needs the same allowance. */
#route-calendar { scroll-margin-top: 72px; }


/* ---------------------------------------------------------------------
   B  Blocks
   A button in the work copy is a bare <a> or <button>; here it is a link
   inside a paragraph block, so the paragraph takes no margin of its own.
   --------------------------------------------------------------------- */
.tagband-cta > p,
.closer-actions > p { margin: 0; }

/* The panel notes are <span>s in the work copy and paragraphs here. */
.plate-head > p.meta { margin: 0; }

/* The calendar's heading row carried these inline in the work copy; a
   group block can carry only its margin inline, so all three live here. */
.cal-headrow { align-items: flex-end; margin-bottom: var(--gap-md); flex-wrap: wrap; }


/* ---------------------------------------------------------------------
   C  The form
   Contact Form 7 wraps each control in an inline span, adds a spinner
   after the submit button, and prints its own response line under the
   form. The Turnstile row has nothing in it until the plugin's keys are
   tested (inc/contact-form.php strips the bare tag).
   --------------------------------------------------------------------- */
.form-live .wpcf7-form-control-wrap { display: block; }
.field-turnstile { margin-top: var(--gap-md); }
.field-turnstile:not(:has(*)) { display: none; }
.form-row { position: relative; }
.form-row .wpcf7-spinner { position: absolute; right: 0; bottom: -30px; margin: 0; }
.form-live .wpcf7-response-output { margin: var(--gap-md) 0 0; border-radius: var(--radius); }

/* ---------------------------------------------------------------------
   D  The route credit
   route-calendar.js adds a line under the calendar crediting
   OpenStreetMap and openrouteservice, whose data places the stops and
   times the drives. The work copy had no data to credit.
   --------------------------------------------------------------------- */
.route-credit { margin: var(--gap-md) 0 0; font-size: var(--fs-meta); color: var(--muted); }
.route-credit a { color: inherit; }


/* ---------------------------------------------------------------------
   E  Empty states
   route-calendar.js fills the rail with a line pointing to the contact
   form when no visit is posted, which the work copy never had to show.
   inc/route-test.php pins a note to the foot of the window while the
   calendar shows sample stops.
   --------------------------------------------------------------------- */
.rail-empty { margin: 0; padding: 14px 0; border-bottom: 1px solid var(--fg); font-size: 15px; }
.rail-empty a { color: inherit; text-decoration: underline; }
.route-test-note {
  position: fixed; left: 50%; bottom: 16px; transform: translateX(-50%); z-index: 50;
  margin: 0; padding: 8px 14px; border-radius: 999px; max-width: calc(100% - 32px);
  background: var(--ink); color: var(--ink-fg); font-size: 13px; text-align: center;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.25);
}


/* ---------------------------------------------------------------------
   F  Day details
   route-calendar.js prints each stop's hours and place in its day, adds
   month tabs under the calendar's head, and gives the upcoming visits
   the same date, town and hours. The work copy's square card
   has no room for that, so its rows grow with what they hold.
   --------------------------------------------------------------------- */
.cal { aspect-ratio: auto; }
.cal-grid { flex: none; grid-auto-rows: minmax(116px, auto); }
.day-when { font-family: var(--font-mono); font-size: 10.5px; font-weight: 500; letter-spacing: 0.01em; }
.day.is-selected .day-when { color: var(--on-accent); }
/* a day with several stops stacks them, and its panel lists each under its own town */
.day-stop + .day-stop { margin-top: 6px; }
.detail-list + .detail-town { margin-top: var(--gap-md); }
.cal-tabs { display: flex; flex-wrap: wrap; gap: 6px; padding: 10px 18px; border-bottom: 1px solid var(--border); }
.cal-tab {
  min-height: 32px; padding: 4px 12px; border: 1px solid var(--border); border-radius: 999px;
  background: transparent; color: var(--fg); font-family: var(--font-mono); font-size: 12px;
  letter-spacing: 0.04em; text-transform: uppercase; cursor: pointer;
}
.cal-tab:hover { border-color: var(--fg); }
.cal-tab[aria-pressed="true"] { background: var(--fg); color: var(--surface); border-color: var(--fg); }
.cal-tab-count { text-transform: none; opacity: 0.7; }
.stop-chip.stop-entry { grid-template-columns: 48px minmax(0, 1fr); align-items: start; padding: 10px 0; }
.entry-date { display: grid; justify-items: center; line-height: 1.1; font-family: var(--font-mono); }
.entry-date small { font-size: 10px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--muted); }
.entry-date b { font-family: var(--font-display); font-size: 24px; font-weight: 600; }
.entry-info { display: grid; gap: 1px; min-width: 0; }
.entry-town { font-size: 15px; font-weight: 600; letter-spacing: -0.01em; }
.entry-hours { font-family: var(--font-mono); font-size: 12px; font-variant-numeric: tabular-nums; }
@media (max-width: 720px) {
  .cal-grid { grid-auto-rows: auto; }
  .day-when { font-size: 12px; }
}


/* ---------------------------------------------------------------------
   G  Booking
   From the owner's 2026-09-30 review. The calendar marks weekends with
   no stop as days off; each stop's panel leads with a booking request,
   which the contact form takes with the day, town, phone and notes; the
   About page shows a strip of work photos where the owner band was. The
   calendar sits closer under the tagline band than the work copy had it.
   --------------------------------------------------------------------- */
.tagband { padding-bottom: 12px; }
.calsection { padding-top: 20px; }

.day.is-off {
  cursor: default;
  background: repeating-linear-gradient(135deg, transparent 0 6px, var(--fg-soft) 6px 7px);
}
.day.is-off .day-num { opacity: .5; }
.detail-actions .btn-primary { width: 100%; }
@media (max-width: 720px) { .day.is-off { display: none; } }

.bio-work .container > h2 { margin-bottom: var(--gap-xs); }
.bio-work .container > .lead { margin: 0 0 var(--gap-lg); max-width: 60ch; }
.work-grid { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: var(--gap-lg); }
.work-grid .plate-img { aspect-ratio: 4 / 3; }
/* The work strip's photos are square shots, so they keep their own shape rather than the 4:5
   crop the business band's plate takes. */
.work-grid .plate-photo img { aspect-ratio: 1 / 1; }
@media (max-width: 1100px) { .work-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 560px) { .work-grid { grid-template-columns: 1fr; } }

/* The finder's nearby rows: the drive time on its own line under the miles. */
.nearby-dist .nearby-drive { display: block; }

/* A photograph in a plate: core/image's figure carries the plate classes, and the picture takes
   the placeholder's heavy border. The photos are portrait phone shots, so the business band's
   plate is cropped to 4:5 rather than the placeholder's landscape 5:4. */
.plate-photo { margin: 0; }
.plate-photo img {
  display: block; width: 100%; height: auto; aspect-ratio: 4 / 5; object-fit: cover;
  border: 2px solid var(--fg); border-radius: var(--radius-lg);
}
.plate-photo .wp-element-caption { margin: var(--gap-sm) 0 0; text-align: left; }

/* The booking request comes in three steps, each under its own heading: who, where and when, and
   what needs sharpening. */
.pf-step { margin: var(--gap-lg) 0 0; padding-top: var(--gap-md); border-top: 1px solid var(--border); font-family: var(--font-display); }
.pf-step:first-of-type { margin-top: 0; padding-top: 0; border-top: 0; }.pf-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--gap-md); margin-top: var(--gap-md); }
@media (max-width: 620px) { .pf-grid { grid-template-columns: 1fr; } }
.pf-grid .field, #field-notes, #field-tools, #field-how { min-width: 0; }
#field-notes, #field-tools, #field-how { margin-top: var(--gap-md); }

/* Visit or mail-in: CF7's radio list drawn as two cards, the picked one filled. */
.pf-choices { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--gap-sm); }
@media (max-width: 520px) { .pf-choices { grid-template-columns: 1fr; } }
.pf-choices .wpcf7-list-item { margin: 0; }
.pf-choices label {
  display: flex; align-items: center; gap: 10px; min-height: 52px; padding: 10px 14px; cursor: pointer;
  border: 2px solid var(--fg-line); border-radius: var(--radius); background: var(--surface); font-weight: 600;
}
.pf-choices label:has(input:checked) { border-color: var(--fg); background: color-mix(in oklch, var(--accent) 22%, var(--surface)); }
.pf-choices input { width: 18px; height: 18px; margin: 0; accent-color: var(--fg); }

/* What needs sharpening: a count per kind of tool, with − and + from booking.js. */
.pf-qty { border: 2px solid var(--fg); border-radius: var(--radius); background: var(--surface); overflow: hidden; }
.pf-qty-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 12px; align-items: center; padding: 10px 12px 10px 16px; }
.pf-qty-row + .pf-qty-row { border-top: 1px solid var(--border); }
.pf-qty-row.is-set { background: color-mix(in oklch, var(--accent) 14%, var(--surface)); }
.pf-qty-row label { min-width: 0; cursor: pointer; }
.pf-qty-row strong { display: block; font-size: 15px; }
.pf-qty-row small { display: block; font-size: 12.5px; color: var(--muted); }
.pf-qty-input { display: inline-flex; align-items: center; border: 1px solid var(--fg-line); border-radius: 8px; }
.pf-qty-input .wpcf7-form-control-wrap { display: block; }
.pf-qty-input .qty-input {
  width: 56px; height: 42px; border: 0; background: transparent; color: var(--fg); text-align: center;
  font-family: var(--font-mono); font-size: 16px; font-weight: 600; font-variant-numeric: tabular-nums; -moz-appearance: textfield;
}
.pf-qty-input .qty-input::-webkit-inner-spin-button, .pf-qty-input .qty-input::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
.pf-qty-step {
  width: 42px; height: 42px; border: 0; border-radius: 7px; background: transparent; color: var(--fg); cursor: pointer;
  font-family: var(--font-mono); font-size: 18px; font-weight: 600; line-height: 1;
}
.pf-qty-step:hover { background: var(--fg-soft); }
.pf-qty-step:focus-visible, .pf-qty-input .qty-input:focus-visible { outline: 2px solid var(--fg); outline-offset: -2px; }
.pf-qty-other { padding: 4px 16px 14px; background: color-mix(in oklch, var(--accent) 14%, var(--surface)); }
.pf-qty-other[hidden] { display: none; }
.pf-qty-total {
  display: flex; justify-content: flex-end; margin: 0; padding: 10px 16px; border-top: 2px solid var(--fg);
  font-family: var(--font-mono); font-size: 13px; font-variant-numeric: tabular-nums;
}
/* The server's "no count" answer lands on the first count; it shows once, under the table. */
.pf-qty-row .wpcf7-not-valid-tip { display: none; }
#field-tools:has(#qty-hair.wpcf7-not-valid) > .field-error { display: block; }
.textarea.notes { min-height: 104px; }
.field-hint { margin: 6px 0 0; font-size: 12.5px; color: var(--muted); }
.pf-actions {
  position: relative; display: flex; align-items: center; justify-content: space-between;
  gap: var(--gap-md); flex-wrap: wrap; margin-top: var(--gap-md);
}
.pf-actions .btn {
  min-height: 52px; min-width: 190px; font-family: var(--font-mono); font-size: 13px;
  letter-spacing: .12em; text-transform: uppercase;
}
.pf-actions .wpcf7-spinner { position: absolute; right: 0; bottom: -30px; margin: 0; }
@media (max-width: 620px) { .pf-actions .btn { width: 100%; } }

/* Each label says whether its field is required: a solid tag for those that are, an outlined one
   for the rest and for the street address, which only a shop visit needs. */
.field-tag {
  display: inline-block; margin-left: 6px; padding: 2px 6px; vertical-align: 1px;
  border: 1px solid var(--muted); border-radius: 3px;
  font-size: 10px; letter-spacing: .1em; color: var(--muted);
}
.field-tag.is-required { background: var(--fg); border-color: var(--fg); color: var(--surface); }

/* What the form still needs, listed above the Send button once it is pressed (booking.js). */
.form-todo {
  margin-top: var(--gap-md); padding: 14px 16px;
  background: var(--surface); border: 2px solid var(--fg); border-left-width: 8px;
  border-radius: var(--radius);
}
.form-todo[hidden] { display: none; }
.form-todo-head { margin: 0 0 6px; font-weight: 700; }
.form-todo ul { margin: 0; padding-left: 1.2em; }
.form-todo li + li { margin-top: 4px; }
.form-todo a { color: var(--fg); text-decoration: underline; text-underline-offset: 3px; }


/* ---------------------------------------------------------------------
   H  Masthead width
   site.css stacks the masthead into three rows below 1120px, while the
   pages go to their desktop columns at 920px, so a 920-1119px window
   showed the phone header over a desktop page. The split band fits from
   920px once its links stay on one line, so it starts there with the
   pages. Between 920 and 1119px this undoes the NARROW block in site.css
   by restating the desktop values from the masthead rules above it; the
   two are kept in step by hand, so a re-sync that changes either one
   changes this block too.

   At 920px the right flank is too narrow for its link and button on one
   row, so three values ease in from smaller ones and reach the desktop
   figures at 1010px: the mark from 190px to 226px, the room left for
   the yellow rules from 40px to 64px (the rule stands 34px out), and the
   flank's gap from 6px to 12px. The header grows with them instead of
   stepping.
   --------------------------------------------------------------------- */
@media (min-width: 920px) {
  .masthead .variant .nav a { white-space: nowrap; }
}
@media (min-width: 920px) and (max-width: 1119px) {
  .masthead { --slant-run: 28px; }
  .masthead .variant .band {
    grid-template-columns: 1fr auto 1fr; justify-items: normal; isolation: isolate;
  }
  .masthead .variant .band .lock {
    --lg-w: clamp(190px, calc(190px + (100vw - 920px) * .4), 226px); padding: 0;
  }
  .masthead .variant .nav { gap: 6px; }
  .masthead .variant .nav a { font-size: 14px; }

  .masthead .variant .nav-left, .masthead .variant .nav-right {
    padding-block: 22px; background: none; clip-path: none;
  }
  .masthead .variant .nav-left {
    justify-content: flex-end; padding-left: var(--gutter);
    padding-right: clamp(40px, calc(40px + (100vw - 920px) * .267), 64px);
  }
  .masthead .variant .nav-right {
    justify-content: flex-start; padding-right: var(--gutter);
    padding-left: clamp(40px, calc(40px + (100vw - 920px) * .267), 64px);
    gap: clamp(6px, calc(6px + (100vw - 920px) * .067), 12px);
  }

  .masthead .variant .mid::before, .masthead .variant .mid::after,
  .masthead .variant .band::before, .masthead .variant .wedge::before { display: block; }
  .masthead .variant .wedge { padding: 22px; isolation: isolate; position: relative; }

  .masthead .variant .is-condensed .band .lock { --lg-w: 126px; }
}

/* "What we sharpen": the home page band between the tagband and the route calendar, which the work
   copy does not have. Each list item is a name in <strong> and its line of text; the grid puts the
   text beside the name, as an anonymous grid item. A work photo added to the band as a
   figure.whatwe-photo before .whatwe-copy takes the left column; without one the list takes the row.
   The photo fills the height of the text beside it rather than keeping its own shape: the image is
   taken out of flow, so the copy sets the row and the picture is cropped to it, and the two line up
   at every width. Stacked on a phone it goes back to a 4:5 plate. */
.whatwe { padding-block: clamp(40px, 6vw, 72px) clamp(24px, 3vw, 40px); }
.whatwe-grid { display: grid; gap: var(--gap-xl); align-items: center; }
.whatwe-grid:has(> .whatwe-photo) { align-items: stretch; }
.whatwe-grid:has(> .whatwe-photo) { grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); }
.whatwe-photo { margin: 0; position: relative; min-height: 340px; }
.whatwe-photo img {
  position: absolute; inset: 0; display: block; width: 100%; height: 100%; object-fit: cover;
  object-position: 50% 45%; border: 2px solid var(--fg); border-radius: var(--radius-lg);
}
.whatwe-copy { align-self: center; }
.whatwe-list { list-style: none; margin: var(--gap-lg) 0 0; padding: 0; border-top: 2px solid var(--fg); }
.whatwe-list li {
  display: grid; grid-template-columns: minmax(0, 13rem) minmax(0, 1fr); gap: var(--gap-md);
  margin: 0; padding-block: var(--gap-md); border-bottom: 1px solid var(--border); line-height: 1.55;
}
.whatwe-list strong { font-family: var(--font-display); font-size: 22px; font-weight: 600; line-height: 1.2; }
.whatwe-more { margin: var(--gap-md) 0 0; }
.whatwe-more a { font-weight: 600; color: var(--fg); text-underline-offset: 3px; }
@media (max-width: 820px) {
  .whatwe-grid:has(> .whatwe-photo) { grid-template-columns: 1fr; }
  .whatwe-photo { max-width: 420px; min-height: 0; aspect-ratio: 4 / 5; }
}
@media (max-width: 520px) {
  .whatwe-list li { grid-template-columns: 1fr; gap: 4px; }
}

/* The stacked masthead (below 920px): the pages row ends in a slant that cuts its bottom edge and
   the contact row starts with one that cuts its top, so links centred in their boxes sat low in the
   first and high in the second (12px of room above against 2px below). Moving each by a quarter of
   the slant centres them in what
   shows. Same weight as site.css's NARROW rules, and later, so these win. */
@media (max-width: 919px) {
  .masthead .variant .nav-left {
    padding-top: calc(12px - var(--slant-run) * .25);
    padding-bottom: calc(12px + var(--slant-run) * .25);
  }
  .masthead .variant .nav-right {
    padding-top: calc(12px + var(--slant-run) * .25);
    padding-bottom: calc(12px - var(--slant-run) * .25);
  }
  /* Scrolled, the bar condenses to 10px rows and a 15px slant through site.css's
     .f-wedgecap .is-condensed rule, which outweighs the two above; these match its weight. */
  .masthead .variant .is-condensed .nav-left {
    padding-top: calc(10px - var(--slant-run) * .25);
    padding-bottom: calc(10px + var(--slant-run) * .25);
  }
  .masthead .variant .is-condensed .nav-right {
    padding-top: calc(10px + var(--slant-run) * .25);
    padding-bottom: calc(10px - var(--slant-run) * .25);
  }

  /* Across, each row is centred on the screen: equal padding both sides, scrolled or not. The
     condensed bar otherwise keeps the desktop's 44px on its logo side through site.css's
     .v-wedge-capped-rule .is-condensed rule, which pushes the pages row left and the contact row
     right once the page scrolls; the condensed selectors here match its weight and come later. */
  .masthead .variant .nav-left, .masthead .variant .is-condensed .nav-left,
  .masthead .variant .nav-right, .masthead .variant .is-condensed .nav-right {
    padding-left: 12px;
    padding-right: 12px;
  }
}
