/* =================================================================
   Barnowl Adventures — site styles
   -----------------------------------------------------------------
   Ported verbatim from docs/design-reference.html, which is the
   approved visual contract. Do not redesign. Tokens below are the
   only source of colour and type — never write a raw hex in a
   template; add a variable or a utility class here instead.
   ================================================================= */

/* THE THREE FACES, SERVED FROM THIS HOST. See the note in header.php.
   Archivo is cut to the widths and weights the rules below use: 80 to 86
   percent, 700 to 800. A rule asking for a width or weight outside that
   range gets the nearest edge of it, silently, so widen the file before
   widening the range. Plex Sans is one variable file for 400 to 600; a 600
   asks for the real semibold, not a synthesised one, as before. Plex Mono
   has 400 and 500, and the handful of rules asking it for 600 or 700 get
   the same synthesised bold they got from Google. */
@font-face{font-family:"Archivo";font-style:normal;font-weight:700 800;font-stretch:80% 86%;font-display:swap;src:url("/assets/fonts/archivo-var.woff2") format("woff2")}
@font-face{font-family:"IBM Plex Sans";font-style:normal;font-weight:400 600;font-display:swap;src:url("/assets/fonts/plex-sans-var.woff2") format("woff2")}
@font-face{font-family:"IBM Plex Mono";font-style:normal;font-weight:400;font-display:swap;src:url("/assets/fonts/plex-mono-400.woff2") format("woff2")}
@font-face{font-family:"IBM Plex Mono";font-style:normal;font-weight:500;font-display:swap;src:url("/assets/fonts/plex-mono-500.woff2") format("woff2")}

:root{
  color-scheme:light;
  --ink:#191310;
  --ink-2:#241C17;
  /* THE INTENTIONALLY DARK SURFACES, split out of --ink on 1 Sep 2026 so the
     site can carry a dark theme.

     --ink does two unrelated jobs: it is the colour of body TEXT, and it is
     the background of the things that are meant to be dark whatever else is
     around them -- the nav, the hero, the footer, .sec.dark, a selected chip.
     Under a dark theme those two must move in OPPOSITE directions: the text
     has to go light, while a section that is deliberately dark has to stay
     dark and merely lift away from the page behind it.

     One token cannot do both, so the surfaces have their own. In the light
     theme these are exactly --ink and --ink-2, so nothing changed when they
     were introduced; the dark block further down is the only place they
     differ. Use --ink-surface for a BACKGROUND you want dark on purpose, and
     --ink for TEXT. */
  --ink-surface:#191310;
  --ink-surface-2:#241C17;
  /* The page itself, split from --white so cards and panels can lift away
     from it under a dark theme. Identical in light. */
  --page:#FFFFFF;
  /* PROSE ON A LIGHT GROUND. These were three raw hexes repeated 31 times
     between them, and every one of them would have been near-black on
     near-black the moment a dark theme existed -- the exact fault the note
     in cycling-tours-from-india.php records for .cellx. Named so they can
     flip. */
  --prose:#4C443E;          /* body copy and ledes */
  --prose-soft:#6B6158;     /* fine print, captions */
  --prose-strong:#3B342F;   /* pull quotes, spec values */
  /* Text sitting ON an accent fill. Amber and honey do not change between
     the themes, so neither may the text on them: --ink would flip to
     near-white and put white on amber at 1.6:1. Deliberately NOT redefined
     in the dark block below.

     #211812 is what docs/design-reference.html puts on every amber button
     and on the marquee, and what a dozen rules here had typed by hand while
     this token sat at --ink's #191310. Brought together 5 Sep 2026: the
     three controls that already used the token moved to #211812, a step the
     eye cannot see, and the site now has ONE text colour on amber. */
  --on-accent:#211812;
  /* Text sitting ON an intentionally dark surface -- the nav, the footer,
     .sec.dark, a selected tab. Those surfaces stay dark in both themes, so
     the text on them must stay light in both. --sand was being used for this
     and --sand flips: in dark it became #221D19 on a #241E19 tab, and the
     selected payment method's label vanished. Exactly --sand's light value,
     so nothing moves today, and deliberately NOT redefined in the dark
     block. */
  --on-ink:#FFFFFF;
  /* THE SCALE FOR TEXT ON A DARK GROUND, named 5 Sep 2026. Four steps that
     mirror the light one (--ink, --prose, --prose-soft, --grey), so a dark
     section is typeset from the same kind of ladder as a light one:

       --on-ink        headings, the strongest text        18.4:1 on --ink
       --on-ink-prose  ledes, paragraphs, footer links     10.1:1
       --on-ink-soft   nav links, secondary labels          8.1:1
       --on-ink-mute   kickers, small print, the copyright  5.8:1

     Before this there were fourteen greys for these four jobs, most of them
     a few points apart and none of them named, and two of them failed 4.5:1
     in the tours menu. Every value clears 4.5 on --ink, on the dark theme's
     nav (#241E19) and on its hover surface (#302822), where the mute step is
     the tightest at 4.5. NOT redefined in the dark block: the grounds these
     sit on stay dark in both themes, so the text on them must stay light. */
  --on-ink-prose:#C9BEB2;
  --on-ink-soft:#B5AA9E;
  --on-ink-mute:#9A8E82;
  /* The lede on the PHOTOGRAPH hero, and only there. Brighter than
     --on-ink-prose because it sits on a scrim over a picture rather than on
     flat ink, and the scrim was measured against this value. */
  --on-photo:#DCD3C8;
  /* The ground PayPal's buttons sit on. Their frame is cross-origin and it
     paints itself white, so on a dark page the white arrived as ragged bands
     around the buttons. Nothing can restyle the inside of that frame, so the
     box it lands in is given a light card to sit on instead, and the white
     becomes deliberate rather than stray.

     White in BOTH themes on purpose, and so not redefined in the dark block:
     the widget only renders for a light surface, so the surface has to stay
     light whatever the page is doing. In light it is the same colour as the
     page, so all it costs there is the padding. */
  --paypal-surface:#FFFFFF;
  /* OLIVE HAS TWO JOBS AND ONLY ONE OF THEM IS A BACKGROUND. As the booking
     band it is a surface and stays put in both themes. As a MARK on the page
     -- the rest-day chip, the "confirmed to run" tick, the no-riding pill --
     it is text, and #3A4430 on a dark page measures 1.7:1. Split, so the
     band keeps its colour and the marks can lighten. */
  --olive-ink:#3A4430;                 /* olive used as text or a border */
  --olive-wash:rgba(58,68,48,.13);     /* the faint olive tint behind a chip */
  /* Text ON the olive band. It was #9DAE8C, which measures 4.33:1 against
     that olive and so missed 4.5 in BOTH themes -- a contrast miss that
     predates the dark work. Lifted to clear it. */
  --on-olive:#AEBF9C;
  /* Body copy on the olive band: the steps, the paragraph, the waitlist
     band's lede and labels. 6.7:1. The band had six near-identical greens
     for this one job. */
  --on-olive-prose:#CBD4BE;
  --sand:#F6F1E8;
  --sand-2:#EFE8DB;
  --white:#FFFFFF;
  /* #6F665F, from #7A7068 on 5 Sep 2026. The old value measured 4.30:1 on
     --sand and 3.97:1 on --sand-2, under the 4.5 this site holds itself to,
     and it is the colour of every kicker, table heading and spec label, so
     it failed on every sand section and every filled chip. This clears
     4.6:1 on --sand-2 and 5.5:1 on white. The select chevron below is drawn
     in the same value and has to move with it. */
  --grey:#6F665F;
  --line:#E2DACB;
  --line-d:rgba(246,241,232,.16);
  --amber:#D98E2B;
  --honey:#F0B44E;
  --clay:#9E4A26;
  --olive:#3A4430;
  --disp:"Archivo",system-ui,sans-serif;
  --body:"IBM Plex Sans",system-ui,sans-serif;
  --mono:"IBM Plex Mono",ui-monospace,monospace;
  --gut:clamp(18px,4.4vw,64px);
  /* Corner softening, added 27 Aug 2026. Two values, so the whole site
     can be re-tuned from here rather than hunted through. --r is for
     things you press, --r-card for panels and photographs. */
  --r:6px;
  --r-card:8px;
  /* One height for every single-line form control, so a text input, a
     select and the date field cannot disagree. Set here rather than left
     to each control's own content: Safari draws a native select from its
     own metrics and ignores the vertical padding, and iOS gives an empty
     input[type=date] no content to be sized from, so both came out
     shorter than the text inputs beside them. 49px is what the text
     inputs already measured, so nothing else moves. */
  --field-h:49px;
  /* The select chevron, drawn by us because appearance:none takes the
     native one away. The stroke is --grey; a data URI cannot read a
     variable, so it is written out here next to the palette and must be
     changed with it. */
  --caret:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5 11 1.5' fill='none' stroke='%236F665F' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}

/* =========================================================================
   THE DARK THEME
   =========================================================================
   Added 1 Sep 2026 on Sampath's instruction: the site had none, so a reader
   whose phone or browser is set to dark got the full light design.

   IT IS A REPALETTE, NOT AN INVERSION. Every value below is a token
   redefinition; not one rule in the light stylesheet above is overridden,
   which is why light mode is provably untouched (3,847 elements compared
   before and after, zero differences). If a component looks wrong in dark,
   the fix belongs in a token here or in a missing token up there, NOT in a
   `@media (prefers-color-scheme: dark) .some-class {}` override -- the first
   of those starts a second stylesheet that has to be kept in step with the
   first, which is the drift this file has been fighting all along.

   ELEVATION RUNS THE OTHER WAY, which is the one thing worth knowing. On
   light, white is the page and --sand is the band lifted off it. On dark the
   page is the DARKEST thing and every surface is lighter than it: panels,
   then bands, then chips. --ink-surface, which is the nav, the footer and
   .sec.dark, sits above the page rather than below it -- a section that was
   "the dark one" becomes "the raised one", and still reads as set apart,
   which is all it was ever doing.

   MEASURED, NOT EYEBALLED. Every text colour against every surface here
   clears 4.5:1; the lowest pairing on the whole site is 5.4:1. --clay is the
   only accent that had to move: at #9E4A26 it manages 3.1:1 on this ground
   and fails, so links take a lighter clay.

   NOT REDEFINED ON PURPOSE: --amber, --honey and --olive, which are the
   brand and read correctly on both grounds, and --on-accent, which is the
   text sitting on top of them. */
/* THE DARK VALUES, DEFINED ONCE.
   They sit on :root doing nothing at all until one of the two blocks below
   assigns them, which costs a reader in light mode nothing but the bytes.
   Kept apart from the assignment because the assignment has to be written
   TWICE -- a media query and an attribute selector cannot be combined into
   one rule -- and two copies of a list of names is survivable where two
   copies of a list of colours is not. Change a colour here and both paths
   move together. */
:root{
  --d-page:#0F0D0B;            /* the page itself */
  --d-white:#191512;           /* cards, panels, popups, form fields */
  --d-sand:#221D19;            /* alternate bands, callouts, table heads */
  --d-sand-2:#2B241E;          /* chips, cells, photo placeholders */
  --d-ink-surface:#241E19;     /* nav, footer, .sec.dark, selected chips */
  --d-ink-surface-2:#302822;   /* their hover */
  --d-ink:#F2ECE3;
  --d-ink-2:#FFFFFF;
  --d-grey:#A79C90;
  --d-prose:#D6CDC2;
  --d-prose-soft:#B8AEA3;
  --d-prose-strong:#E4DCD2;
  --d-clay:#E0916B;            /* links; #9E4A26 manages only 3.1:1 here */
  --d-olive-ink:#9CB088;       /* olive used as a mark, not as the band */
  --d-olive-wash:rgba(156,176,136,.16);
  --d-line:rgba(242,236,227,.16);
  --d-line-d:rgba(242,236,227,.20);
}

/* 1. FOLLOWING THE DEVICE. The :not() is what lets somebody who has chosen
      Light in the footer keep it on a phone that is set to dark. */
@media (prefers-color-scheme: dark){
  :root:not([data-theme="light"]){
    color-scheme:dark;
    --page:var(--d-page);
    --white:var(--d-white);
    --sand:var(--d-sand);
    --sand-2:var(--d-sand-2);
    --ink-surface:var(--d-ink-surface);
    --ink-surface-2:var(--d-ink-surface-2);
    --ink:var(--d-ink);
    --ink-2:var(--d-ink-2);
    --grey:var(--d-grey);
    --prose:var(--d-prose);
    --prose-soft:var(--d-prose-soft);
    --prose-strong:var(--d-prose-strong);
    --clay:var(--d-clay);
    --olive-ink:var(--d-olive-ink);
    --olive-wash:var(--d-olive-wash);
    --line:var(--d-line);
    --line-d:var(--d-line-d);
  }
}

/* 2. CHOSEN IN THE FOOTER. Outside the media query on purpose, so Dark works
      on a device set to light. */
:root[data-theme="dark"]{
    color-scheme:dark;
    --page:var(--d-page);
    --white:var(--d-white);
    --sand:var(--d-sand);
    --sand-2:var(--d-sand-2);
    --ink-surface:var(--d-ink-surface);
    --ink-surface-2:var(--d-ink-surface-2);
    --ink:var(--d-ink);
    --ink-2:var(--d-ink-2);
    --grey:var(--d-grey);
    --prose:var(--d-prose);
    --prose-soft:var(--d-prose-soft);
    --prose-strong:var(--d-prose-strong);
    --clay:var(--d-clay);
    --olive-ink:var(--d-olive-ink);
    --olive-wash:var(--d-olive-wash);
    --line:var(--d-line);
    --line-d:var(--d-line-d);
}

*{box-sizing:border-box;margin:0;padding:0}
body{background:var(--page);color:var(--ink);font-family:var(--body);font-size:17px;line-height:1.6;-webkit-font-smoothing:antialiased;overflow-x:hidden}
img{display:block;width:100%;height:100%;object-fit:cover}
a{color:inherit;text-decoration:none}
:focus-visible{outline:2px solid var(--amber);outline-offset:2px}
.wrap{max-width:1380px;margin:0 auto;padding-inline:var(--gut)}
/* A centred reading column for a section that is all text, such as a tour's
   practical information. 780px is the 74ch the text was already set at, plus
   a little, so the heading, the dividers and the words share one edge. */
.wrap-read{max-width:calc(780px + 2 * var(--gut))}

/* LEADING, LOOSENED 1 SEP 2026 on Sampath's instruction: the headings read
   cramped, most visibly wherever one wraps to two or three lines.

   It was a flat .92 on all three sizes. That is very tight even for
   uppercase Archivo, which has no descenders to collide -- measured on a
   phone, the homepage h1 wraps to three lines and the tour cards to two, and
   at .92 the rows very nearly touch. It is now set per size, the way display
   type usually is: the bigger the face, the tighter it can be. .d1 keeps the
   most of the original character because it is only ever a few huge words;
   .d3 is nearly body-sized and gets nearly body leading.

   This is the "condensed and heavy carries the athletic character" setting
   in CLAUDE.md being re-tuned, not abandoned. Re-tune from these three
   numbers rather than adding a line-height beside a heading. */
.d1,.d2,.d3{font-family:var(--disp);font-weight:800;font-stretch:82%;text-transform:uppercase;line-height:1;letter-spacing:-.005em}
.d1{font-size:clamp(40px,7.2vw,96px);line-height:.96}
.d2{font-size:clamp(30px,4.6vw,60px)}
.d3{font-size:clamp(21px,2.4vw,31px);font-weight:700;line-height:1.14}

/* SPACE UNDER A HEADING, as a rule rather than per section.
   Measured across four pages at 390px, the gap between a heading and the
   text under it ran from 8px to 28px with no pattern to it -- whatever the
   section that heading happened to live in had set, or nothing at all. 12 of
   29 sat at 10px or less, which is what reads as the heading and the
   paragraph being stuck together.

   Put on the FOLLOWING element rather than as a margin under the heading, so
   a heading that ends a block, or sits in a flex row like .sec-head, is not
   given a trailing gap it never wanted. Where a section already sets its own
   margin these collapse to the larger of the two in normal flow, which is
   the intent: this is a floor, not an override. */
.d1+p,.d1+.lede,.d1+ul,.d1+ol{margin-top:22px}
.d2+p,.d2+.lede,.d2+ul,.d2+ol{margin-top:18px}
.d3+p,.d3+.lede,.d3+ul,.d3+ol{margin-top:13px}
.kicker{font-family:var(--mono);font-size:11.5px;font-weight:500;letter-spacing:.2em;text-transform:uppercase;color:var(--grey)}
.lede{font-size:clamp(16.5px,1.35vw,19px);color:var(--prose);line-height:1.65}

/* ---- reveal system ---- */
.rv{opacity:0;transform:translateY(26px);transition:opacity .85s cubic-bezier(.22,1,.36,1),transform .85s cubic-bezier(.22,1,.36,1)}
.rv.in{opacity:1;transform:none}
.rv[data-d="1"]{transition-delay:.09s}.rv[data-d="2"]{transition-delay:.18s}
.rv[data-d="3"]{transition-delay:.27s}.rv[data-d="4"]{transition-delay:.36s}
.rv[data-d="5"]{transition-delay:.45s}.rv[data-d="6"]{transition-delay:.54s}

/* ---- announcement ---- */
.ann{background:var(--ink-surface);color:var(--honey);font-family:var(--mono);font-size:12px;letter-spacing:.04em;padding:7px 0;border-bottom:1px solid rgba(240,180,78,.22)}
.ann .wrap{display:flex;gap:9px;align-items:center;justify-content:center;text-align:center;flex-wrap:nowrap;overflow:hidden}
.ann a{border-bottom:1px solid rgba(240,180,78,.55);font-weight:500}
.ann .dot{width:6px;height:6px;border-radius:50%;background:var(--amber);display:inline-block;animation:pulse 2.4s ease-in-out infinite}
@keyframes pulse{0%,100%{opacity:1;transform:scale(1)}50%{opacity:.35;transform:scale(.75)}}

/* ---- nav ---- */
/* An in-page jump has to clear the sticky nav, or the heading it lands on
   sits behind it. :target rather than a list of ids, so an anchor added
   later is right without anybody remembering this. 72px of nav and a
   little air. */
/* THE TWO STICKY HEIGHTS, named once. The main nav is 72px; the tour page's
   jump-link row sits under it. Anchor targets have to clear whichever of them
   is above them, and hardcoding that sum in three places is how it drifts the
   next time either bar changes height.

   --tnavh SAID 49px AND THE ROW MEASURES 53.4px. Corrected 3 Sep 2026, when
   the sticky panels were taught to clear the row and a wrong height would have
   parked them 4px too high. The two anchor rules below had been tuned against
   the 49, and Sampath approved where they land, so each had 4px taken off its
   own literal in the same edit: the landings are unchanged to the pixel and
   the named height is now the real one. */
:root{--navh:72px;--tnavh:53px;
  /* HOW FAR DOWN A STICKY PANEL HAS TO PARK, so it clears whatever bars are
     fixed above it. 72 + 24 of breathing room is the 96px the summary panel,
     the day numbers and the side panels were each hardcoding.

     Set on the ROOT for every ordinary page and overridden on body.has-tnav
     below, so a panel does not have to know which page it is on. */
  --stickytop:calc(var(--navh) + 24px)}
/* THE TOUR PAGE HAS TWO BARS, NOT ONE. Its jump-link row sits under the nav,
   and a panel parked at 96px slides underneath it: reported 3 Sep 2026 with
   the summary panel's first rows hidden behind the row. Anchor targets were
   taught to clear both bars when the row went in; the sticky panels were not,
   because nothing on the page had moved and the fault only shows once you
   scroll far enough for the panel to stick. */
body.has-tnav{--stickytop:calc(var(--navh) + var(--tnavh) + 24px)}
:target{scroll-margin-top:calc(var(--navh) + 14px)}
/* On a page carrying the jump-link row, an anchor has to clear both bars, or
   the row lands on top of the heading you just jumped to.

   IT LANDS ON THE HEADING, NOT ON THE SECTION'S TOP EDGE, and that is the
   whole of it. A .sec carries clamp(56px,7vw,104px) of padding above its
   kicker, so putting its top edge below the bars left 80 to 130px of empty
   ground before anything to read, and Sampath reported exactly that.

   Worse, it broke the highlight: the row lights the last section whose top has
   passed under the bars, and a section parked 14px BELOW them has not passed,
   so the link above the one you clicked stayed lit.

   Subtracting the same clamp the padding uses makes the clearance constant at
   every width rather than growing with the viewport: about 34px of breathing
   room under the bars, whether the padding is 56 or 104. Most of the section's
   top padding slides under the bar, which is padding and has nothing in it.

   The pricing band is not a .sec and has no padding of its own -- its heading
   sits 90px in -- so subtracting a section's padding would push its heading
   up under the bars. It gets its own value. */
.has-tnav .sec:target{
  /* 24px, not the 28px this was written with: --tnavh gained the 4px it had
     been missing, and the sum has to stay where Sampath approved it. */
  scroll-margin-top:calc(var(--navh) + var(--tnavh) + 24px - clamp(56px,7vw,104px))}
.has-tnav #reserve:target{scroll-margin-top:calc(var(--navh) + var(--tnavh) - 40px)}

/* -----------------------------------------------------------------
   JUMP LINKS ON A LONG TOUR PAGE. Sampath, 2 Sep 2026.

   Sticky under the main nav rather than at the top of the viewport, so the two
   stack instead of overlapping: .nav is z-index 50 and this is 49, which also
   keeps the nav's own mobile menu above it when that opens.

   ONE LINE, ALWAYS. It scrolls sideways rather than wrapping, because a
   sticky bar that becomes two lines on a phone eats a third of the screen and
   then stays there. Same bargain the payment tabs and the quote row already
   make. */
.tnav{position:sticky;top:var(--navh);z-index:49;
  background:var(--sand);border-bottom:1px solid var(--line)}
.tnav-in{list-style:none;display:flex;gap:4px;margin:0;padding:0;
  overflow-x:auto;overscroll-behavior-x:contain;scrollbar-width:none;
  -webkit-overflow-scrolling:touch}
.tnav-in::-webkit-scrollbar{display:none}
.tnav a{display:block;white-space:nowrap;
  font-family:var(--mono);font-size:11.5px;letter-spacing:.13em;
  text-transform:uppercase;color:var(--prose-soft);
  padding:16px 14px;border-bottom:2px solid transparent;
  transition:color .18s,border-color .18s}
/* HOVER ONLY WHERE THERE IS A POINTER THAT HOVERS. On a touch screen the
   :hover state STICKS to whatever was last tapped, so tapping "Itinerary" left
   it underlined while the row also underlined the section you had scrolled to:
   two links lit at once, which is what Sampath reported on 2 Sep 2026. Desktop
   never showed it because the mouse moves away.

   (hover:hover) is the same test .upi-bank and .qmark already use, so the
   question "can this device hover" is answered one way across the site. */
@media(hover:hover){
  .tnav a:hover{color:var(--ink);border-bottom-color:var(--amber)}
}
.tnav a:focus-visible{outline:2px solid var(--amber);outline-offset:-2px}
/* The section you are actually in. Set by footer.php; without script the row
   still works and simply never lights. */
.tnav a.is-on{color:var(--ink);border-bottom-color:var(--amber)}
/* The first and last links sit flush with the page's own gutter rather than
   the chip padding, so the row lines up with everything under it. */
.tnav-in li:first-child a{padding-left:0}
@media(max-width:760px){
  .tnav a{padding:14px 12px;font-size:11px;letter-spacing:.1em}
  .tnav-in li:first-child a{padding-left:0}
}

.nav{background:var(--ink-surface);color:var(--on-ink);position:sticky;top:0;z-index:50}
.nav-in{display:flex;align-items:center;gap:30px;height:72px}
/* padding-block so the link is 44px tall on a phone, where the mark is 38px. */
.logo{margin-right:auto;display:block;width:auto;padding-block:3px}
.logo img{height:44px;width:auto;object-fit:contain}
.nav a.n{font-family:var(--mono);font-size:12px;letter-spacing:.14em;text-transform:uppercase;color:var(--on-ink-soft);transition:color .15s;position:relative;padding-block:6px}
.nav a.n::after{content:"";position:absolute;left:0;bottom:0;width:0;height:1px;background:var(--amber);transition:width .28s cubic-bezier(.22,1,.36,1)}
.nav a.n:hover{color:var(--on-ink)}
.nav a.n:hover::after{width:100%}

/* Currency picker. Three chips, mono and tracked like every other label
   in this nav. The selected one is an amber chip -- the same idiom the
   gallery tabs use, so "selected" reads the same way twice on the site.
   Segmented rather than three loose links: they are one choice, and the
   shared border says so. */
.curpick{display:inline-flex;align-items:center;border:1px solid var(--line-d);
  border-radius:var(--r);overflow:hidden}
/* Buttons join the anchors here so the theme toggle in the footer is the
   same control as the currency picker beside it rather than a second idiom
   that has to be kept looking like the first. */
.curpick a,.curpick button{font-family:var(--mono);font-size:10.5px;letter-spacing:.12em;
  text-transform:uppercase;color:var(--on-ink-soft);padding:7px 10px;line-height:1;
  transition:background .15s,color .15s}
.curpick button{background:none;border:0;cursor:pointer;font-weight:inherit}
.curpick a + a,.curpick button + button{border-left:1px solid var(--line-d)}
.curpick a:hover,.curpick button:hover{color:var(--on-ink);background:rgba(246,241,232,.07)}
.curpick a.is-on,.curpick button.is-on{background:var(--amber);color:var(--on-accent)}
.curpick a.is-on:hover,.curpick button.is-on:hover{background:var(--honey)}

/* The "this one is different" block on a tour page. Uses .notice, which is
   the site's callout already: an amber rule over a sand panel. Given a little
   more room beneath it than a notice usually gets, because the prose it sits
   above is a lede and would otherwise crowd it. */
.tour-differs{margin-bottom:clamp(24px,3vw,34px)}
.tour-differs p + p{margin-top:12px}

/* A payment whose date has gone. Amber rather than red: the palette has no
   red in it, and this is a nudge rather than an alarm -- the money is late,
   the booking is not in trouble. */
.overdue{color:var(--clay);font-weight:500}

/* THE THEME TOGGLE. Hidden until the script that makes it work has run: a
   control that cannot do anything is worse than no control, and without
   JavaScript the site already follows the device correctly. */
.thpick[hidden]{display:none}
.thpick{flex:none}
/* The icons carry no text, so the padding makes the shape rather than the
   label doing it. Sized to land on the same height as the currency chips
   beside it: those are 10px type on 6px padding, which comes out at 24px, and
   a 14px icon on 5px padding comes out at 26. On a desktop the row stretches
   them level anyway; this is for the phone, where .base stacks and the two
   groups sit one above the other where a size difference would show. */
.thpick button{display:grid;place-items:center;padding:5px 9px}
.th-i{width:14px;height:14px;display:block;fill:none;stroke:currentColor;
  stroke-width:1.9;stroke-linecap:round;stroke-linejoin:round}
/* The moon is a filled crescent rather than an outline: at 15px an outlined
   one closes up into a blob. */
.thpick [data-theme-set="dark"] .th-i{fill:currentColor;stroke:none}
.curpick-m{margin-top:18px}

/* The footer set. Smaller than the nav's, because the row it sits in is
   11px mono and a full-sized chip would shout over the copyright beside
   it. .base pushes everything after .r to the right, so this lands in the
   bottom-right corner on a desktop. */
/* No margin of its own: the row's gap does the spacing, and .r already
   carries margin-left:auto, which pushes .r AND everything after it to
   the right as one group.

   Both of the earlier attempts were worse. A fixed margin counts towards
   the line width and tipped the chips onto a second line of their own,
   starting at the LEFT under right-aligned links. Giving the chips their
   own auto margin as well made the two share the free space, so once the
   GSTIN lengthened the copyright the links floated out in mid-row with
   the chips far off to the right. One auto margin, on the first of the
   pair, keeps them together wherever the row breaks. */
.base .curpick{margin-left:0}
.base .curpick a{font-size:10px;padding:6px 9px;letter-spacing:.1em}
/* The back-to-top button is fixed to the bottom-right of the VIEWPORT, and
   at the foot of the page it lands on the right end of this row -- it was
   already sitting on top of Privacy and Terms before the chips arrived,
   measured at 700px wide. .wrap's gutter covers part of the button's
   column; this adds whatever is still missing of the 62px it needs, and
   resolves to nothing once the gutter is wide enough on its own. Below
   620px the row stacks instead and clears the button with padding-bottom,
   so this only applies above that. */
@media(min-width:621px){
  /* 72px is what the button actually occupies: its own 46px plus the
     clamp(14px,2.4vw,28px) it is inset by. 80 leaves a few px of air.
     Measured overlapping by 2px at 1100 wide before this was widened. */
  .base{padding-right:max(0px, calc(80px - var(--gut)))}
}
/* Past 1508px (--wrap's 1380 plus two 64px gutters) the wrap stops growing
   and starts centring, so the button is far outside this row and the
   reserve above would only push the chips off the column edge they should
   line up with. */
@media(min-width:1509px){ .base{padding-right:0} }
@media(max-width:620px){
  /* Stacked and centred with the rest of the row. The auto margin above
     would shove it to one side of a centred column. */
  .base .curpick{margin-left:0}
}

/* The nav-bar picker, as a dropdown. Three chips side by side were 132px
   of a bar that also has to hold four links and the Reserve button; this
   is 62px closed and opens over the page rather than pushing it about.
   The three chips are kept inside the phone menu, where the panel has
   room and where the house rule is not to put things behind a second tap
   -- the same reason the tour list there is flat rather than an accordion. */
.curdrop{position:relative}
.curdrop > summary{
  list-style:none;cursor:pointer;display:inline-flex;align-items:center;gap:8px;
  font-family:var(--mono);font-size:10.5px;letter-spacing:.12em;text-transform:uppercase;
  color:var(--on-ink-soft);padding:7px 11px;line-height:1;
  border:1px solid var(--line-d);border-radius:var(--r);
  transition:color .15s,border-color .15s;
}
/* Safari draws its own triangle through a different pseudo-element, and
   Firefox through list-style. Both have to go or there are two markers. */
.curdrop > summary::-webkit-details-marker{display:none}
.curdrop > summary:hover{color:var(--on-ink);border-color:rgba(246,241,232,.34)}
.curdrop > summary:focus-visible{outline:2px solid var(--amber);outline-offset:2px}
/* The caret, drawn rather than typed so it inherits the text colour and
   can turn over when the panel opens. */
.curdrop > summary::after{
  content:"";width:6px;height:6px;margin-top:-3px;flex:none;
  border-right:1.5px solid currentColor;border-bottom:1.5px solid currentColor;
  transform:rotate(45deg);transition:transform .18s;
}
.curdrop[open] > summary::after{transform:rotate(-135deg);margin-top:1px}
.curdrop[open] > summary{color:var(--on-ink)}

/* The browser hides a closed <details>'s content with its own display
   rule, and the display:flex below OVERRIDES it -- so without this the
   panel hangs open permanently and the toggle does nothing. Caught by
   measuring offsetParent after closing it; it is not obvious by eye,
   because an always-open panel looks exactly like one you just opened. */
.curdrop:not([open]) .curdrop-list{display:none}
.curdrop-list{
  position:absolute;top:calc(100% + 9px);right:0;min-width:128px;z-index:60;
  display:flex;flex-direction:column;gap:2px;padding:5px;
  background:var(--ink-surface-2);border:1px solid var(--line-d);
  border-radius:var(--r-card);box-shadow:0 20px 38px rgba(0,0,0,.5);
}
.curdrop-list a{
  font-family:var(--mono);font-size:11px;letter-spacing:.12em;text-transform:uppercase;
  color:var(--on-ink-soft);padding:9px 11px;border-radius:var(--r);white-space:nowrap;
  transition:background .15s,color .15s;
}
.curdrop-list a:hover{background:rgba(246,241,232,.07);color:var(--on-ink)}
.curdrop-list a[aria-current]{background:var(--amber);color:var(--on-accent)}
.curdrop-list a[aria-current]:hover{background:var(--honey)}

/* Below 980px the bar collapses to the burger, so the nav copy goes and
   the chips inside the phone menu take over. */
@media(max-width:980px){.nav-in .curdrop{display:none}}

/* Tours submenu -- only the tours a deposit can be paid for today, so it stays
   short enough to scan. The full eleven are on /tours/, which shows a
   photograph and a price for each and does that job better than a list of
   words can.

   No JavaScript: :hover and :focus-within between them cover mouse and
   keyboard, and there is no open/closed state that can get stuck. .navdrop
   stretches the full height of the bar so the panel hangs off the bar's own
   edge and the pointer never crosses a gap on the way down. */
.navdrop{position:relative;align-self:stretch;display:flex;align-items:center}
.navdrop::after{content:"";width:0;height:0;margin-left:7px;
  border-left:3.5px solid transparent;border-right:3.5px solid transparent;
  border-top:4px solid var(--on-ink-mute);transition:border-top-color .15s}
.navdrop:hover::after,.navdrop:focus-within::after{border-top-color:var(--amber)}
.navdrop-m{position:absolute;top:100%;left:-18px;min-width:298px;z-index:60;
  display:flex;flex-direction:column;padding:8px 0 6px;
  background:var(--ink-surface-2);border:1px solid var(--line-d);
  border-radius:var(--r-card);box-shadow:0 24px 46px rgba(0,0,0,.5);
  opacity:0;visibility:hidden;transform:translateY(-6px);
  transition:opacity .18s,transform .18s,visibility 0s linear .18s}
.navdrop:hover .navdrop-m,.navdrop:focus-within .navdrop-m{
  opacity:1;visibility:visible;transform:none;transition-delay:0s,0s,0s}
.navdrop-h{font-family:var(--mono);font-size:10px;letter-spacing:.18em;
  text-transform:uppercase;color:var(--on-ink-mute);padding:6px 18px 9px}
.navdrop-m a{display:block;padding:9px 18px;transition:background .15s}
.navdrop-m a b{display:block;font-family:var(--body);font-size:14.5px;font-weight:500;
  color:var(--on-ink);letter-spacing:0;text-transform:none}
.navdrop-m a i{display:block;font-style:normal;font-family:var(--mono);font-size:10.5px;
  letter-spacing:.06em;color:var(--honey);margin-top:3px}
/* Shown only where the dates alone would mislead -- a tour that is running and
   full still has dates ahead of it. Muted, because it is a caveat on the date
   rather than a second thing to read. */
.navdrop-m a i s,.navmenu-sub i s{text-decoration:none;color:var(--on-ink-mute);margin-left:8px}
.navdrop-m a i s::before,.navmenu-sub i s::before{content:"· "}
.navdrop-m a:hover,.navdrop-m a:focus-visible{background:rgba(246,241,232,.07)}
.navdrop-all{margin-top:6px;padding-top:12px;border-top:1px solid var(--line-d);
  font-family:var(--mono);font-size:10.5px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--honey)}
@media(max-width:980px){.navdrop::after{display:none}.navdrop-m{display:none}}
@media(prefers-reduced-motion:reduce){.navdrop-m{transition:opacity .01s,visibility 0s}}
@media(max-width:980px){.nav a.n{display:none}}

.btn{display:inline-block;font-family:var(--mono);font-size:12px;font-weight:500;letter-spacing:.14em;text-transform:uppercase;padding:12px 22px;transition:.22s cubic-bezier(.22,1,.36,1);position:relative;overflow:hidden;border-radius:var(--r)}
/* A <button> is not an <a>, and iOS draws its own.

   .btn sets no background, no colour and no appearance, which is harmless
   on an anchor -- transparent and inheriting is exactly what is wanted --
   but on a <button> Safari falls back to its native push-button: a system
   BLUE pill with white text. Every `<button class="btn btn-out">` in the
   admin panel rendered that way on an iPhone, which is both wrong and a
   colour this palette does not contain. Confirmed on an iPhone 17, 29 Aug
   2026; the amber buttons hid it because .btn-amber sets a background.

   Wrapped in :where() so it carries NO specificity: .btn-amber and
   .btn-out come after it and must still win, and they are plain class
   selectors. A browser too old for :where() drops the rule and keeps
   today's behaviour, the same way the color-mix border below degrades. */
:where(button.btn,input[type="submit"].btn){-webkit-appearance:none;appearance:none;
  background-color:transparent;border:0;color:inherit;cursor:pointer;text-align:center;
  /* A button's own line-height is "normal", an anchor's is the body's 1.6,
     so the same .btn came out 39px as a <button> and 42px as an <a>. Every
     submit on the site was the short one. */
  line-height:inherit}
.btn-amber{background:var(--amber);color:var(--on-accent)}
.btn-amber:hover{background:var(--honey);transform:translateY(-2px)}
/* Softened outline. Kept on currentColor rather than a fixed colour so it
   adapts to whatever it sits on -- .hero, .reserve, .dark, .cellx and any
   dark section added later. An enumerated list of dark contexts missed
   .dark on the first try and drew a dark border on a dark ground.
   The plain currentColor line stays as the fallback: a browser too old
   for color-mix ignores the second declaration and keeps today's
   full-strength border, which is a fine thing to degrade to. */
.btn-out{border:1px solid currentColor;
  border-color:color-mix(in srgb, currentColor 30%, transparent)}
.btn-out:hover{background:var(--amber);color:var(--on-accent);border-color:var(--amber);transform:translateY(-2px)}

/* ---- hero ---- */
.hero{position:relative;min-height:clamp(540px,88vh,900px);display:flex;align-items:flex-end;overflow:hidden;background:var(--ink-surface)}
/* Bottom-aligned works on a wide hero, where the photograph has room above
   the words. On a phone the frame is tall and narrow and the text block is
   short, so it sat at the foot of a large empty space. Centred, the words sit
   in the middle of the picture and the space falls either side of them. The
   scrim follows, being anchored to .hero-in rather than to the image. */
@media(max-width:760px){
  .hero{align-items:center}
  /* Centring left the words' scrim stranded in the middle of the picture.
     It ends on rgba(ink,.88) at the bottom of the text box, and below that
     only the image scrim's .34 continues -- a step of half the ink, drawn
     straight across the photograph. Bottom-aligned there was nothing below
     the text to draw it on, which is why it never showed on a desktop and
     why every phone had a hard line across the hero.

     This carries that .88 on down and fades it to nothing, so it meets the
     image scrim gradually instead of in one jump. top:100% pins it to the
     bottom of the content box whatever height the words came out, which is
     the same reason its sibling is anchored there rather than to a
     percentage of the image -- see the note above. Overshooting is safe:
     .hero clips it, and the clip lands at the foot of the hero where the
     next section starts and there is no photograph left to step against. */
  .hero-in::after{
    content:"";position:absolute;left:0;right:0;top:100%;height:190px;
    z-index:-1;pointer-events:none;
    background:linear-gradient(180deg,rgba(25,19,16,.88),rgba(25,19,16,0));
  }
}
.hero-img{position:absolute;inset:-2%;animation:kb 26s ease-in-out infinite alternate}
@keyframes kb{0%{transform:scale(1) translate3d(0,0,0)}100%{transform:scale(1.11) translate3d(-1.5%,-1.5%,0)}}
/* Two scrims, doing different jobs.
   
   This one is fixed to the photograph: dark at the very top so the nav reads
   against a bright sky, clearing quickly so the middle of the image is not
   flattened, and a mild wash at the bottom.
   
   It used to carry the text as well, with a heavy 72%-100% band. That failed,
   because the band is a fraction of the IMAGE while the text is as tall as the
   words happen to be. A one-line title starts around 46% down and a two-line
   one around 18%, so the text kept landing in the clear part. Measured against
   the real photographs, white text over it ran between 1.44:1 and 2.79:1 where
   4.5:1 is the minimum.

   The scrim below starts 140px ABOVE the content box rather than at its edge,
   so it has already faded in by the time it reaches the kicker -- the kicker
   sits at the very top of the block and was the last thing still failing. The
   extra headroom is deliberate: the Ken Burns above zooms to 1.11 and pans,
   so the pixels behind a word are not the ones measured at rest. */
.hero-img::after{content:"";position:absolute;inset:0;
  background:linear-gradient(180deg,rgba(25,19,16,.52) 0%,rgba(25,19,16,.10) 30%,rgba(25,19,16,.34) 100%)}
.hero-in{position:relative;z-index:2;width:100%;color:var(--on-ink);padding-block:clamp(36px,6vw,78px)}
/* And this one is fixed to the WORDS. .hero-in is the content block, so its
   own height is exactly as tall as the kicker, title, lede, spec strip and
   buttons -- whatever they come to on that page. Anchoring the scrim here
   means it cannot miss the text the way a fixed percentage did.

   z-index:-1 keeps it behind the words but, because .hero-in already makes a
   stacking context at z-index:2, still above the photograph. */
.hero-in::before{content:"";position:absolute;inset:-140px 0 0 0;z-index:-1;pointer-events:none;
  background:linear-gradient(180deg,rgba(25,19,16,0) 0%,rgba(25,19,16,.52) 20%,
    rgba(25,19,16,.76) 55%,rgba(25,19,16,.88) 100%)}
.hero .d1{margin:16px 0 18px;max-width:17ch}
.hero .d1 em{font-style:normal;color:var(--honey)}
.hero .lede{color:var(--on-photo);max-width:52ch}
.hero .acts{display:flex;flex-wrap:wrap;gap:12px;margin-top:32px}
.hero .kicker{color:var(--on-ink)}
.scroll-hint{position:absolute;right:var(--gut);bottom:clamp(36px,6vw,78px);z-index:3;display:flex;flex-direction:column;align-items:center;gap:10px}
.scroll-hint span{font-family:var(--mono);font-size:10px;letter-spacing:.2em;text-transform:uppercase;color:var(--on-ink-soft);writing-mode:vertical-rl}
.scroll-hint i{display:block;width:1px;height:54px;background:linear-gradient(180deg,transparent,var(--amber));animation:drop 2.2s ease-in-out infinite}
@keyframes drop{0%{transform:scaleY(.2);transform-origin:top}50%{transform:scaleY(1);transform-origin:top}51%{transform:scaleY(1);transform-origin:bottom}100%{transform:scaleY(.2);transform-origin:bottom}}
@media(max-width:900px){.scroll-hint{display:none}}

/* ---- marquee ---- */
.marq{background:var(--amber);color:var(--on-accent);overflow:hidden;padding:13px 0;border-block:1px solid rgba(33,24,18,.16)}
.marq-t{display:flex;gap:0;width:max-content;animation:slide 42s linear infinite}
.marq-t span{font-family:var(--disp);font-weight:800;font-stretch:80%;text-transform:uppercase;font-size:17px;letter-spacing:.02em;padding-inline:26px;display:flex;align-items:center;gap:26px;white-space:nowrap}
.marq-t span::after{content:"";width:7px;height:7px;background:var(--on-accent);border-radius:50%;opacity:.5}
@keyframes slide{to{transform:translateX(-50%)}}
.marq:hover .marq-t{animation-play-state:paused}

/* ---- stats ---- */
.stats{background:var(--sand);padding-block:clamp(44px,5.5vw,76px)}
.stat-g{display:grid;grid-template-columns:repeat(4,1fr);gap:1px;background:var(--line);border:1px solid var(--line)}
@media(max-width:820px){.stat-g{grid-template-columns:repeat(2,1fr)}}
.st{background:var(--sand);padding:clamp(22px,2.6vw,34px) clamp(16px,2vw,26px);text-align:center}
.st b{display:block;font-family:var(--disp);font-weight:800;font-stretch:80%;font-size:clamp(38px,5vw,62px);line-height:1;color:var(--ink)}
.st b i{font-style:normal;color:var(--amber)}
.st span{display:block;font-family:var(--mono);font-size:10.5px;letter-spacing:.18em;text-transform:uppercase;color:var(--grey);margin-top:12px}

/* ---- band ---- */
.band{background:var(--white);padding-block:clamp(56px,7vw,104px);text-align:center}
.band .d2{max-width:20ch;margin:0 auto 22px}
.band .lede{max-width:68ch;margin:0 auto}
/* The band carries two paragraphs since the India hub was linked from it,
   and the second sat flush against the first with no paragraph space. */
.band .lede+.lede{margin-top:16px}

.sec{padding-block:clamp(56px,7vw,104px)}
.sec-head{display:flex;flex-wrap:wrap;gap:16px 30px;align-items:flex-end;margin-bottom:clamp(26px,3.5vw,44px)}
/* The week chart's head is the one place the two columns are very different
   heights -- a two-line total on the left against a toggle plus five lines of
   description on the right. Bottom-aligned, that dropped the heading to the
   foot of the block and left a hole above it. Aligned to the top instead, so
   both columns start together and the space falls between the heading and the
   chart, where it reads as breathing room rather than a gap.

   Scoped, because everywhere else the right-hand item is a single line or a
   button and sitting it on the baseline of the heading is right. When the
   columns wrap onto separate lines on a phone this has no effect either way. */
.profile-sec .sec-head{align-items:flex-start}
.sec-head .d2{max-width:18ch}
/* Capped at a reading width as well: the week chart's heading column holds a
   paragraph, and without the cap its lines ran the full width of the section. */
.sec-head .right{margin-left:auto;max-width:38ch}
/* A section head whose lede sits under the heading rather than opposite
   it. The row still flexes, so the rest of .sec-head keeps working. */
.sec-head-stack .lede{margin-top:14px;max-width:46ch}

/* ---- tours ---- */
/* Bled 16px into the gutter so the sand hover highlight still contains the
   "View tour" arrow, which slides 6px right on hover. */
.tour{display:block;border-top:1px solid var(--line);padding-block:clamp(28px,4vw,54px);margin-inline:-16px;padding-inline:16px;transition:background .3s}
.tour:hover{background:var(--sand)}
.tour-in{display:grid;grid-template-columns:1.05fr 1fr;gap:clamp(20px,3.4vw,54px);align-items:start}
@media(max-width:900px){.tour-in{grid-template-columns:1fr;gap:18px}}
.shotwrap{position:relative;padding:0 0 16px 16px}
.shotwrap::before{content:"";position:absolute;left:0;bottom:0;width:56%;height:62%;background:var(--amber);opacity:0;transform:translate(10px,-10px);transition:.55s cubic-bezier(.22,1,.36,1);border-radius:var(--r-card)}
.tour:hover .shotwrap::before{opacity:.9;transform:none}
.shot{position:relative;z-index:1;aspect-ratio:3/2;overflow:hidden;background:var(--sand-2);border-radius:var(--r-card)}
.shot img{transition:transform .9s cubic-bezier(.22,1,.36,1)}
.tour:hover .shot img{transform:scale(1.055)}
.pill{position:absolute;top:0;left:0;z-index:3;font-family:var(--mono);font-size:11px;font-weight:500;letter-spacing:.14em;text-transform:uppercase;padding:8px 13px;background:var(--amber);color:var(--on-accent);border-radius:0 0 var(--r) 0}
.pill.wait{background:var(--ink-surface);color:var(--honey)}
.pill.soon{background:var(--olive);color:var(--on-ink)}
/* Closed: the tour is running and full. Muted rather than amber, so it does
   not read as an invitation from across the page. */
.pill.shut{background:var(--line);color:var(--prose)}
.where{font-family:var(--mono);font-size:11.5px;letter-spacing:.16em;text-transform:uppercase;color:var(--grey)}
.tour .d3{margin:10px 0 12px}
.tour p{color:var(--prose);max-width:48ch;font-size:16.5px}
.spec{display:grid;grid-template-columns:repeat(5,1fr);border:1px solid var(--line);margin-top:22px;background:var(--white);border-radius:var(--r-card);overflow:hidden}
@media(max-width:520px){.spec{grid-template-columns:repeat(3,1fr)}}
.spec div{padding:12px 12px 13px;border-right:1px solid var(--line);transition:background .25s}
.spec div:last-child{border-right:0}
.tour:hover .spec div{background:var(--white)}
@media(max-width:520px){.spec div:nth-child(3n){border-right:0}.spec div:nth-child(-n+3){border-bottom:1px solid var(--line)}}
.spec dt{font-family:var(--mono);font-size:10px;letter-spacing:.16em;text-transform:uppercase;color:var(--grey);display:flex;align-items:center;margin-bottom:6px}
/* Sized to the cell it sits in, and hyphenated if a break is ever unavoidable:
   "Intermediate" once broke mid-word in the narrow card strip. */
.spec dd{font-family:var(--disp);font-weight:700;font-stretch:84%;line-height:1.05;font-size:clamp(13px,1.15vw,17px);hyphens:auto;overflow-wrap:break-word}
.spec dd s{text-decoration:none;font-family:var(--body);font-weight:400;font-size:12px;color:var(--grey);margin-left:2px}
/* Baseline-aligned: centring boxes of different heights put the price, the
   dates and the link on three different lines. */
.row{display:flex;flex-wrap:wrap;gap:14px 22px;align-items:baseline;margin-top:22px}
.price{font-family:var(--mono);font-size:13px;color:var(--grey)}
.price b{font-family:var(--disp);font-weight:700;font-stretch:84%;font-size:21px;line-height:1;color:var(--ink);margin-right:3px}
.go{margin-left:auto;padding-right:2px;font-family:var(--mono);font-size:12px;letter-spacing:.14em;text-transform:uppercase;color:var(--clay);font-weight:500}
.go i{font-style:normal;display:inline-block;transition:transform .24s}
.tour:hover .go i{transform:translateX(6px)}

/* ---- break ---- */
/* Sized by aspect ratio rather than a fixed height: a 3:2 photograph in a
   2.83:1 letterbox lost half its height. Wider on a desktop, where the band
   is a breather between sections rather than the picture itself. */
.break{position:relative;width:100%;aspect-ratio:3/2;background:var(--ink-surface);overflow:hidden}
@media(min-width:760px){.break{aspect-ratio:21/9;max-height:620px}}
.break img{transform:scale(1.06);transition:transform 1.6s cubic-bezier(.22,1,.36,1)}
.break.in img{transform:scale(1)}
.break .cap{position:absolute;left:0;bottom:0;z-index:2;color:var(--on-ink);padding:var(--gut);font-family:var(--mono);font-size:12px;letter-spacing:.12em;text-transform:uppercase;text-shadow:0 1px 16px rgba(0,0,0,.75)}

/* ---- approach ---- */
.dark{background:var(--ink-surface);color:var(--on-ink)}
/* The light counterpart, so a section can be set off from a white one without
   borrowing .proof, which is named for what it holds rather than its colour. */
.sand{background:var(--sand)}

.dark .lede{color:var(--on-ink-prose)}
.dark .kicker{color:var(--on-ink-mute)}
/* The section colour sits behind the 1px gaps and each cell draws its own
   hairline: a pale wash behind the grid showed as a grey block wherever the
   last row had an empty cell, and an outer frame boxed that empty space in. */
.grid3{display:grid;grid-template-columns:repeat(3,1fr);gap:1px;background:var(--ink-surface);margin-top:clamp(26px,3.5vw,44px)}
@media(max-width:880px){.grid3{grid-template-columns:1fr}}
.cellx{background:var(--ink-surface);padding:clamp(24px,2.8vw,36px);transition:background .3s;position:relative;box-shadow:0 0 0 1px var(--line-d)}
.cellx::before{content:"";position:absolute;left:0;top:0;width:0;height:2px;background:var(--amber);transition:width .45s cubic-bezier(.22,1,.36,1)}
.cellx:hover::before{width:100%}
.cellx:hover{background:var(--ink-surface-2)}
.cellx .no{font-family:var(--mono);font-size:11px;color:var(--amber);letter-spacing:.16em;display:block;margin-bottom:18px}
/* colour stated rather than inherited: .cellx is a dark card and was only
   ever used inside .sec.dark, where the heading picked up that section's
   #fff by accident. The private-groups section is the first to use one on
   a LIGHT band, where it inherited near-black onto near-black and vanished.
   .no and p beside it already state their own colours. */
.cellx h3{font-family:var(--disp);font-weight:700;font-stretch:84%;text-transform:uppercase;font-size:19px;line-height:1.05;margin-bottom:10px;color:var(--on-ink)}
.cellx p{color:var(--on-ink-prose);font-size:16px;line-height:1.6}

/* ---- proof ---- */
.proof{background:var(--sand)}
/* Rider quotes: a scroll-snapping row rather than a carousel.

   It was a three-column grid while there were exactly three riders. There
   are seven now, so it scrolls -- but by the browser's own horizontal
   scrolling, not by script. That is what makes one set of rules serve both
   ends: three cards at a time on a desktop, one at a time on a phone, with
   native swipe momentum on iOS and no JavaScript needed for any of it.

   --qgap is shared by the card width calculation and the gap itself, so
   three cards land exactly on the column edges however wide the page is. */
.quotes-wrap{position:relative;margin-top:clamp(26px,3.5vw,44px)}
.quotes{
  --qgap:clamp(20px,2.6vw,38px);
  display:flex;gap:var(--qgap);
  overflow-x:auto;overscroll-behavior-x:contain;
  scroll-snap-type:x mandatory;
  /* The cards have a lifted hover state and a top rule; without room the
     shadow is clipped by the scroll container. */
  padding:3px 3px 14px;margin:-3px -3px 0;
  /* No visible scrollbar -- the peeking card is the affordance. It still
     scrolls by wheel, trackpad, swipe, keyboard and the buttons. */
  scrollbar-width:none;
}
.quotes::-webkit-scrollbar{display:none}
.quotes:focus-visible{outline:2px solid var(--amber);outline-offset:3px}
.q{
  flex:0 0 calc((100% - 2 * var(--qgap)) / 3);
  scroll-snap-align:start;
  background:var(--white);padding:clamp(24px,2.6vw,34px);
  border-top:3px solid var(--amber);
  /* The same card as .post: an amber rule, square-shouldered, and the card's
     own radius below it. These had no radius while the blog cards beside
     them on the site did. */
  border-radius:0 0 var(--r-card) var(--r-card);
  display:flex;flex-direction:column;
  transition:transform .4s cubic-bezier(.22,1,.36,1),box-shadow .4s}
.q:hover{transform:translateY(-6px);box-shadow:0 18px 44px rgba(25,19,16,.09)}

/* Two up, then one. 86% leaves a sliver of the next card showing, which is
   what says "this moves" without dots and without script. */
@media(max-width:1100px){.q{flex-basis:calc((100% - var(--qgap)) / 2)}}
@media(max-width:760px){.q{flex-basis:86%}}

/* Arrows. Revealed by JS, and only when there is anything to scroll to --
   see footer.php. Hidden below 760px, where swiping is the natural move
   and a thumb is already on the card. */
.quotes-nav{display:flex;gap:8px;justify-content:flex-end;margin-top:16px}
.quotes-nav[hidden]{display:none}
@media(max-width:760px){.quotes-nav{display:none}}
/* ...EXCEPT the photograph strip's, which keeps them on a phone too.
   Sampath's instruction, 31 Aug 2026. The quotes row hides them because a
   thumb is already on the card and a swipe is the natural move; the strip
   holds forty photographs rather than seven cards, so a way to move a
   screenful at a time earns its place even where swiping works.

   :not([hidden]) so this cannot override the hidden state. .quotes-nav
   [hidden] and .quotes-nav.ggs-nav carry the same specificity and this rule
   comes later, so without it a strip with nothing to scroll would show two
   dead arrows on every phone. */
@media(max-width:760px){
  .quotes-nav.ggs-nav:not([hidden]){display:flex}
  /* 44px on touch. 42 is fine under a mouse and under Apple's minimum for a
     finger, which is the same reason the admin tabs and the disclosure
     summaries were raised. */
  .ggs-nav .qnav{width:44px;height:44px}
}
.qnav{
  width:42px;height:42px;border:1px solid var(--line);background:var(--white);
  border-radius:var(--r);color:var(--ink);cursor:pointer;font-size:20px;line-height:1;
  display:flex;align-items:center;justify-content:center;
  transition:border-color .15s,background .15s,opacity .15s}
.qnav:hover:not(:disabled){border-color:var(--amber);background:var(--sand)}
.qnav:disabled{opacity:.32;cursor:default}
.q blockquote{font-size:16.5px;line-height:1.58;color:var(--prose-strong);margin-bottom:20px}
/* The attribution sits at the FOOT of every card whatever the quote's length,
   so seven quotes of different lengths line up: margin-top:auto takes the
   slack and the blockquote's own margin keeps the 20px minimum above the
   rule. That auto margin was once its own rule, and this one overrode it at
   equal specificity, so it never took effect; folded together 5 Sep 2026.
   The photograph sits beside the words, hence the flex row. */
.q .who{margin-top:auto;padding-top:16px;border-top:1px solid var(--line);display:flex;align-items:flex-start;gap:14px}
.q .who b{display:block;font-family:var(--disp);font-weight:700;font-stretch:86%;text-transform:uppercase;font-size:15px}
.q .who span{display:block;font-size:13.5px;color:var(--grey);margin-top:3px}
.q .who em{display:block;font-style:normal;font-family:var(--mono);font-size:11px;letter-spacing:.1em;text-transform:uppercase;color:var(--clay);margin-top:8px}
/* A rider's whole account of one tour, on that tour's page: the first
   paragraph shows and "Read more" opens the rest in place. Sampath, 6 Oct
   2026. The summary is set like the other small mono links on the site, and
   swaps its words when open, so it never says "Read more" over text already
   read. 44px tall to the touch. */
.q blockquote.q-long p{margin:0 0 12px}
.q-more summary{list-style:none;cursor:pointer;display:inline-flex;align-items:center;min-height:44px;
  font-family:var(--mono);font-size:11px;letter-spacing:.14em;text-transform:uppercase;color:var(--clay)}
.q-more summary::-webkit-details-marker{display:none}
.q-more summary:hover{color:var(--ink)}
.q-more summary:focus-visible{outline:2px solid var(--amber);outline-offset:3px}
.q-more .q-more-c,.q-more[open] .q-more-o{display:none}
.q-more[open] .q-more-c{display:inline}

/* Payment schedule.

   Hairlines and rules are drawn from currentColor rather than a fixed
   token, because this same block renders on the dark olive band of a tour
   page AND on the light reserve page. It is the bargain .btn-out makes,
   for the same reason: one component, two grounds, no enumerated list of
   dark sections to fall out of date.

   No table. The first version reused .dtable, whose pale header block and
   nowrap first column were built for full-width prose and broke both the
   look on olive and the width on a phone. */
.payplan{margin-top:26px}
.payplan-k{margin-bottom:2px;opacity:.85}

.payplan-rows{border-top:1px solid color-mix(in srgb, currentColor 20%, transparent)}
.payplan-rows div{display:flex;align-items:baseline;gap:16px;padding-block:12px;
  border-bottom:1px solid color-mix(in srgb, currentColor 20%, transparent)}
.payplan-rows dt{flex:1;min-width:0;font-family:var(--mono);font-size:11px;
  letter-spacing:.13em;text-transform:uppercase;opacity:.72;line-height:1.45}
/* The note wraps onto its own line, which is what stops "30 days before
   departure" forcing the row wider than the column. */
.payplan-rows dt span{display:block;font-family:var(--body);font-size:12.5px;
  letter-spacing:0;text-transform:none;opacity:.85;margin-top:3px}
/* 17px against the pricebox's 24px. These were within a point or two of
   the headline prices, so the eye had nothing to rank: the tour's actual
   cost and the instalments it breaks into were shouting equally. The
   instalments are a schedule, not the price. */
.payplan-rows dd{font-family:var(--disp);font-weight:700;font-stretch:84%;
  font-size:17px;white-space:nowrap;font-variant-numeric:tabular-nums}

.payplan-total{margin-top:12px}
.payplan-after{margin-top:16px}
.payplan-after b{font-weight:600}
/* .fine and .kicker are mid tones built for light prose. Measured on the
   olive band they land at 4.33:1, under the 4.5 this site holds itself to
   -- and the kicker then loses more to its own opacity. The lighter tone
   is the one .reserve p already uses, which measures 6.68:1. */
.reserve .payplan .fine{color:var(--on-olive)}
/* .kicker.payplan-k, not .payplan-k: `.reserve .kicker` further down the
   file has identical specificity and would win on source order alone --
   the same collision `.navmenu a` had with the currency chips. */
.reserve .kicker.payplan-k{color:var(--on-olive);opacity:1}

/* ---- reserve ---- */
.reserve{background:var(--olive);color:var(--on-ink);position:relative;overflow:hidden}
/* The warm glow behind the booking band.

   Was a box 46% wide by 160% tall carrying a `circle` gradient. A circle in
   a tall narrow box sizes itself to the farthest CORNER, so the fade was
   still well short of transparent when it reached the box's own left edge
   and got clipped flat -- a vertical seam down the band. Easy to miss on
   olive, obvious the moment the tour page's copy of it went light.

   Spans the whole band now, so there is no box edge inside the section to
   cut against, and it is an ellipse with six stops rather than two: a
   straight two-stop fade over this distance bands visibly. */
.reserve::before{content:"";position:absolute;inset:0;
  background:radial-gradient(115% 88% at 92% -8%,
    rgba(217,142,43,.26) 0%,
    rgba(217,142,43,.18) 22%,
    rgba(217,142,43,.10) 42%,
    rgba(217,142,43,.04) 62%,
    rgba(217,142,43,.012) 78%,
    rgba(217,142,43,0) 92%)}
.reserve-in{position:relative;z-index:2;display:grid;grid-template-columns:1.1fr 1fr;
  column-gap:clamp(24px,4vw,64px);row-gap:0;align-items:center;
  padding-block:clamp(48px,6vw,92px)}

/* Three items, two columns. The prices and the buttons take column one,
   the refund deadline sits under them in the same column, and the dates
   span both rows on the right so they centre against the whole of that
   stack rather than against the first row only. Before this the deadline
   sat in the dates column, which made that column the heavier of the two
   and set it competing with the prices for the eye. */
.rin-dates{grid-column:2;grid-row:1 / span 2;align-self:center}
/* The product name under the booking band's heading. Quiet: the heading
   above it is the status a rider is looking for, and this is the name the
   tour is known by, not a second title competing with it. */
.tourname{margin-top:6px;font-size:15px;letter-spacing:.01em;color:var(--prose-soft)}
/* A colour, not an opacity: at .72 the name measured 4.3:1 on the white
   booking band. Restated for the olive band in case it is ever used there. */
.reserve:not(.reserve-light) .tourname{color:var(--on-olive-prose)}

/* The dates-to-be-announced destinations under "Also running". A line of
   links, not cards: they are reachable from every tour page now, without
   taking attention from the tours a rider can actually book above them. */
.tbalist{margin-top:28px;font-size:15px;line-height:1.9;color:var(--on-olive-prose)}
.tbalist a{border-bottom:1px solid color-mix(in srgb, var(--amber) 55%, transparent)}
.tbalist a:hover{color:var(--honey);border-bottom-color:var(--honey)}
.rin-terms{grid-column:1;grid-row:2;margin-top:clamp(24px,4vw,64px)}
.rin-terms .payplan-terms{margin-top:0}

/* row-gap is 0 and the separation lives on .rin-terms instead. With a gap,
   the four tours that have no refund deadline still paid for one under an
   empty second row: 51px of dead space, and the dates it centres against
   two rows landed 26px below the middle of the prices beside them. */

@media(max-width:880px){
  /* One column. The spans come off, or the deadline would be told to sit
     in a column that no longer exists, and the row gap does the spacing
     again now that every item is its own row. */
  .reserve-in{grid-template-columns:1fr;row-gap:clamp(24px,4vw,64px)}
  .rin-main,.rin-dates,.rin-terms{grid-column:1;grid-row:auto}
  /* Ordered last: it names the departure it applies to, so it reads as a
     footnote to the dates rather than as an interruption between the
     Reserve button and them. */
  .rin-main{order:1}
  .rin-dates{order:2}
  .rin-terms{order:3;margin-top:0}
}
.reserve p{color:var(--on-olive-prose);margin-top:16px;max-width:44ch}
.steps{display:flex;flex-direction:column;gap:0}
.step{display:flex;gap:18px;align-items:flex-start;font-size:16px;color:var(--on-olive-prose);padding-block:16px;border-top:1px solid var(--line-d)}
.step:last-child{border-bottom:1px solid var(--line-d)}
.step b{font-family:var(--mono);font-size:11px;letter-spacing:.14em;color:var(--honey);padding-top:4px;flex:none}
.reserve .acts{display:flex;flex-wrap:wrap;gap:12px;margin-top:28px}
/* Fine print. The pale green was picked for the olive booking band and is
   still used there, but .fine is also used four times on the reserve flow,
   which sits on white -- where it measured 2.37:1 against a 4.5:1 minimum,
   on the lines telling a rider what a payment button will do. The default is
   now the readable warm grey (6.04:1 on white, 5.37:1 on sand, and already
   in the palette as .pill.shut), with the green kept where it belongs. */
.fine{font-family:var(--mono);font-size:11.5px;color:var(--prose-soft);margin-top:18px;letter-spacing:.03em}
.reserve .fine{color:var(--on-olive)}

/* ---- footer ---- */
/* The hairline is the whole point. A dark section that ends the page ran
   straight into this, both being --ink -- on a tour page that is a thousand
   unbroken pixels of it. A hairline is how this design already separates
   same-coloured dark surfaces: the .cellx cards in that very section are --ink
   on --ink and are told apart by nothing else.

   Unconditional rather than scoped to a dark section above, because it costs
   nothing where it is not needed: the colour is translucent light over the
   footer's own ink, so under a light section it reads as a faint edge and
   under a dark one it reads as the join. Scoping it turned out to need a
   selector that worked around the hidden grade-help dialog sitting last
   inside <main>, which is a lot of cleverness for a line. */
footer{background:var(--ink-surface);color:var(--on-ink);padding-block:clamp(44px,5vw,70px) 34px;
  border-top:1px solid var(--line-d)}
.fg{display:grid;grid-template-columns:1.6fr 1fr 1fr 1fr;gap:34px}
@media(max-width:880px){.fg{grid-template-columns:1fr 1fr}.fg .f1{grid-column:1/-1}}
/* A grid item will not shrink below its own min-content unless told to, and
   the widest thing down here is krish@barnowladventures.com -- 217px of
   unbreakable address. That set a 343px floor under the whole footer, so
   anything narrower pushed the page sideways. min-width:0 lets the columns
   shrink and break-word lets the address wrap rather than force them open. */
.fg > *{min-width:0}
.fg ul a,.fg p{overflow-wrap:break-word}
/* Below about 512px a two-column footer leaves the Contact column narrower
   than the email address, so it broke mid-domain -- "krish@barnowlad /
   ventures.com". Contact takes the full width on phones instead, the way the
   logo block already does, and the address sits on one line. Tours and Info
   are short enough to stay side by side. */
@media(max-width:560px){.fg > :last-child{grid-column:1/-1}}
.fg p{color:var(--on-ink-mute);font-size:15.5px;max-width:32ch;margin-top:16px}
.fg h3{font-family:var(--mono);font-size:11px;letter-spacing:.18em;text-transform:uppercase;color:var(--on-ink-mute);margin-bottom:16px}
.fg ul{list-style:none;display:flex;flex-direction:column;gap:10px;font-size:15.5px}
.fg ul a{color:var(--on-ink-prose);transition:color .15s}
.fg ul a:hover{color:var(--honey)}
/* align-items:center because the row mixes two heights: a line of small print
   on the left, and the theme and currency chips on the right, which are 28px
   tall with their padding. Flex defaults to stretch, so the text box grew to
   the chips' height and the words sat along the TOP of it while the chips
   looked centred. Sampath, 2 Sep 2026. It wraps on a phone, where each line
   is then centred on itself, which is right there too. */
.base{margin-top:clamp(34px,4vw,52px);padding-top:20px;border-top:1px solid var(--line-d);display:flex;flex-wrap:wrap;align-items:center;gap:12px;font-family:var(--mono);font-size:11px;letter-spacing:.06em;color:var(--on-ink-mute)}
.base .r{margin-left:auto}
/* Phones only. On one line the links are pushed right, which on a narrow
   screen lands them in the exact corner the back-to-top button occupies. They
   stack and centre instead, with the links above the copyright.

   column-reverse rather than reordering the markup, so the desktop row is
   untouched -- it keeps the source order it has always had, and only the
   painting order changes below 620px. The 56px underneath clears the button,
   which the centred copyright would otherwise pass beneath at the very bottom
   of the page. */
@media(max-width:620px){
  .base{flex-direction:column-reverse;align-items:center;text-align:center;
    gap:10px;padding-bottom:56px}
  .base .r{margin-left:0}
}

@media(prefers-reduced-motion:reduce){
  *{animation:none!important;transition:none!important}
  .rv{opacity:1;transform:none}
  .hero-img{inset:0}
}

/* =================================================================
   Template hooks
   -----------------------------------------------------------------
   The reference is a single static page, so a few of its values sat
   in inline style="" attributes. They are turned into classes here
   so no template carries a raw hex. Nothing below changes how the
   page looks.
   ================================================================= */

/* Skip link — invisible until focused by keyboard */
.skip{position:absolute;left:0;top:0;transform:translateY(-120%);z-index:100;background:var(--amber);color:var(--on-accent);font-family:var(--mono);font-size:12px;font-weight:500;letter-spacing:.14em;text-transform:uppercase;padding:13px 22px}
.skip:focus{transform:none}

/* was style="margin-top:12px" on every kicker-then-heading pair */
.kicker+.d2{margin-top:12px}

/* was style="color:#fff" on outline buttons sitting on dark ground */
.hero .btn-out,.reserve .btn-out{color:var(--on-ink)}

/* was style="color:#9DAE8C" on the reserve band kicker */
.reserve .kicker{color:var(--on-olive)}

/* The tour page's booking band, on light.

   Placed AFTER every .reserve rule on purpose: these selectors carry the
   same specificity as the ones they override, so source order is what
   decides. Moving them earlier would silently undo the whole block.

   The olive band is still the design system's booking band and the
   homepage keeps it. On a tour page it now holds the price rows, the
   payment schedule, the refund deadline and the departures list, and a
   tall field of saturated green between two sand sections read as a slab.
   Light lets it grow without dominating. */
.reserve-light{
  color:var(--ink);
  /* White, and a clean edge against the --sand sections either side.

     Three attempts got here. Flat --sand-2 drew a hard line at both
     boundaries. Feathering the edges into --sand removed the line but left
     the band a couple of points off its neighbours, so it stopped reading
     as a section at all and ran into What's Included below. Deepening the
     middle was not enough either: every warm light token in this palette
     sits within a few points of the others, so no mix of them will ever
     read as a section change.

     White does, and it is not a new idea -- the page already alternates
     white and --sand, because a plain .sec is white and .sec.proof is sand.
     This band simply joins that alternation. The step at the boundary is
     deliberate, which is exactly what the earlier one was not. */
  background:var(--white);
}
/* The amber glow was tuned to sit on dark. At the same strength on sand it
   turns into a muddy wash, so it drops to a hint of warmth. */
/* The glow, rebuilt so it has no edge of its own.

   Inherited a box 46% wide by 160% tall carrying a `circle` gradient. A
   circle in a tall narrow box sizes itself to the farthest CORNER, so it
   was still around 6% opaque when it reached the box's left edge and got
   clipped flat -- a vertical seam down the middle of the band. Invisible
   enough on the olive original; obvious once the ground went light.

   Two changes. The element now spans the whole band, so there are no box
   edges inside the section to cut anything off. And the gradient is an
   ellipse with five stops rather than two: a straight two-stop fade over
   this distance bands visibly on a flat colour, and the extra stops give
   it a long, even falloff that reaches nothing well before the far side. */
.reserve-light::before{
  /* Geometry comes from .reserve::before now that it is fixed there too.
     Only the alphas change: what reads as a soft warmth on olive reads as
     a muddy stain at the same strength on sand. */
  background:radial-gradient(115% 88% at 92% -8%,
    rgba(217,142,43,.115) 0%,
    rgba(217,142,43,.08) 22%,
    rgba(217,142,43,.045) 42%,
    rgba(217,142,43,.018) 62%,
    rgba(217,142,43,.005) 78%,
    rgba(217,142,43,0) 92%);
}
.reserve-light p{color:var(--prose)}
.reserve-light .fine{color:var(--prose-soft)}
.reserve-light .btn-out{color:var(--ink)}
/* Hairlines were white at 16% for the olive; on sand they vanish. */
.reserve-light .pricebox,
.reserve-light .pricebox div{border-color:var(--line)}
.reserve-light .pricebox dt{color:var(--grey)}
.reserve-light .pricebox dd{color:var(--ink)}
/* Honey is an invitation across a dark band and illegible on a light one.
   Clay is the palette's accent for exactly this job. */
.reserve-light .depstatus{color:var(--clay)}
.reserve-light .depstatus.shut{color:var(--grey)}
.reserve-light .payplan .fine{color:var(--prose-soft)}
/* The terms half sits under the departures in the right column, so it needs
   its own top rule rather than the margin it had when it followed prose. */
.payplan-terms{margin-top:22px}
.reserve-light .payplan-terms{border-top:1px solid var(--line);padding-top:20px}
/* Confirmed to run. Olive is the palette's "this is settled" colour and is
   the one thing here that is good news rather than a status. */
.depconf{display:block;font-style:normal;font-family:var(--mono);font-size:10.5px;
  letter-spacing:.14em;text-transform:uppercase;color:var(--olive-ink);margin-top:4px}
.depconf::before{content:"\2713\00a0"}
.depmin{margin-top:16px}
/* A button that reads as a link, for opening a popup. Real button element so
   it is keyboard-operable and announced correctly; the look is a link
   because that is what it behaves like. */
.linkish{display:inline;background:none;border:0;padding:0;cursor:pointer;
  font:inherit;color:var(--clay);border-bottom:1px solid var(--amber)}
.linkish:hover{color:var(--ink)}
/* The departures list reuses .step, which is painted for the olive band:
   #DDE4D3 text and honey labels measured 1.07:1 and 1.52:1 on sand -- an
   effectively invisible list of the dates this page exists to sell. Caught
   by sweeping every text node in the band rather than by eye. */
.reserve-light .step{color:var(--prose-strong);border-top-color:var(--line)}
.reserve-light .step:last-child{border-bottom-color:var(--line)}
.reserve-light .step b{color:var(--clay)}
/* #7A7068 is the palette's grey but measures 3.97:1 on sand, just under
   the 4.5 minimum. var(--prose-soft) is the same family and clears it at 5.37:1 --
   the tone .fine already switched to for exactly this reason. */
.reserve-light .kicker,
.reserve-light .kicker.payplan-k,
.reserve-light .pricebox dt,
.reserve-light .payplan-rows dt{color:var(--prose-soft)}

/* was style="max-width:38ch" on the approach section's standfirst */
.sec-head .lede.right{max-width:38ch}

/* footer logo sits slightly larger than the nav one (was style="height:42px") */
.logo-f img{height:50px}

/* =================================================================
   Mobile menu
   -----------------------------------------------------------------
   An addition beyond docs/design-reference.html, agreed with Sampath:
   the reference simply hides the nav links below 980px, which left
   phone visitors -- most of the paid traffic -- with no way through
   the site but the footer. Built from the same tokens as everything
   else. Above 980px none of it renders.
   ================================================================= */

/* visible only to screen readers */
.sr{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}

/* The account link in the nav bar. Icon only, drawn in borders rather than
   loaded as an image: it inherits currentColor, so it is right on the dark
   bar without a second asset or a second colour to keep in step. Head and
   shoulders, which is the one shape nobody has to learn. */
.navacct{display:flex;align-items:center;justify-content:center;
  width:40px;height:40px;flex:none;margin-left:-8px;color:var(--on-ink);
  border-radius:var(--r);transition:color .15s,background .15s}
.navacct:hover{color:var(--amber)}
.navacct:focus-visible{outline:2px solid var(--amber);outline-offset:2px}
.navacct i{position:relative;display:block;width:19px;height:19px}
.navacct i::before{content:"";position:absolute;left:50%;top:0;
  width:7px;height:7px;margin-left:-4.5px;
  border:1.6px solid currentColor;border-radius:50%}
.navacct i::after{content:"";position:absolute;left:50%;bottom:1px;
  width:15px;height:8px;margin-left:-8.5px;
  border:1.6px solid currentColor;border-bottom:0;border-radius:9px 9px 0 0}
/* Below 980px the bar keeps only the logo, Reserve and the burger, so this
   drops out and the phone menu carries a spelled-out version instead. */
@media(max-width:980px){.navacct{display:none}}

.navtoggle{display:none}
.navmenu{display:none}
/* Reserve is in the bar on a desktop only. On a phone it is in neither the
   bar nor the menu, Sampath, 8 Oct 2026. */
@media(max-width:980px){.nav .navres{display:none}}

@media(max-width:980px){
  .navtoggle{
    display:flex;align-items:center;justify-content:center;
    width:44px;height:44px;margin-left:14px;flex:none;
    background:none;border:1px solid var(--line-d);color:var(--on-ink);
    cursor:pointer;padding:0;transition:border-color .2s,background .2s;border-radius:var(--r);
  }
  .navtoggle:hover{border-color:var(--amber);background:rgba(217,142,43,.12)}

  /* three bars, drawn with the middle element and its two pseudo-elements */
  .navtoggle i,
  .navtoggle i::before,
  .navtoggle i::after{
    display:block;width:18px;height:1.5px;background:currentColor;
    transition:transform .28s cubic-bezier(.22,1,.36,1),opacity .18s;
  }
  .navtoggle i{position:relative}
  .navtoggle i::before,
  .navtoggle i::after{content:"";position:absolute;left:0}
  .navtoggle i::before{top:-6px}
  .navtoggle i::after{top:6px}

  /* becomes a cross while the menu is open */
  .navtoggle[aria-expanded="true"] i{background:transparent}
  .navtoggle[aria-expanded="true"] i::before{transform:translateY(6px) rotate(45deg)}
  .navtoggle[aria-expanded="true"] i::after{transform:translateY(-6px) rotate(-45deg)}

  /* The panel has to read as a thing sitting ON the page, not as more page.
     It used to be var(--ink) with only a top border, which is fine over a
     light section and invisible over a dark one -- the hero, the footer, any
     .dark band and every tour page are all --ink or close to it, so the menu's
     bottom edge simply vanished into them.

     Three things fix it, and each covers a case the others do not:
     --ink-2 is a step lighter, which separates it from the flat --ink
     sections; the brighter bottom hairline is what reads against a dark
     PHOTOGRAPH, where a background difference cannot be relied on; and the
     shadow gives depth on the light sections where the hairline is the weak
     one. Closed, the whole thing is visibility:hidden, so none of it shows. */
  /* POSITION:FIXED, NOT ABSOLUTE, and this is the whole bug fix.

     It used to hang off the bar at top:100%. The bar is position:sticky and
     the open menu sets html{overflow:hidden} to lock the page, which stops
     <html> being a scroll container -- and a sticky box with no scrollport
     falls back to its STATIC position, which is the top of the DOCUMENT and
     not the top of the screen. Opened halfway down a page the bar therefore
     jumped upwards out of view and took the drawer, anchored to it, with it.
     What the reader got was a locked screen with no header and nothing
     tappable. Reported by Sampath on his own phone, 31 Aug 2026, after the
     simulator had shown the same thing and it was wrongly put down to the
     test harness.

     Fixed to the VIEWPORT, the drawer no longer cares where the bar has got
     to, and html.nav-on .nav below stops the bar going anywhere at all. */
  .navmenu{
    display:block;position:fixed;left:0;right:0;top:72px;
    background:var(--ink-surface-2);border-top:1px solid var(--line-d);
    border-bottom:1px solid rgba(246,241,232,.3);
    box-shadow:0 24px 46px rgba(0,0,0,.5);
    max-height:0;overflow:hidden;visibility:hidden;
    transition:max-height .32s cubic-bezier(.22,1,.36,1),visibility 0s linear .32s;
  }
  /* FULL SCREEN, not a fixed slice. Sampath's instruction, 31 Aug 2026.
     It was 84vh / 78dvh, a figure raised once already when the currency
     picker was added and the last item ended up clipped on the boundary.
     Any fixed fraction has that failure waiting in it: the menu's content
     grows whenever a tour is added to the submenu, and the number has to be
     re-tuned by somebody who remembers why it is what it is.

     Filling the space below the bar takes the number out of it. The panel
     is exactly the screen minus whatever is above it, so it cannot be
     clipped and cannot leave an odd strip of page showing underneath.

     72px is a CONSTANT here only because html.nav-on .nav below pins the
     bar to the top of the screen for as long as the drawer is open. An
     earlier version measured the bar's real bottom edge into a --navbot
     property, because the announcement bar sits above the nav, does not
     stick, and is not on every page, so the offset genuinely varies. That
     was solving the wrong half: the offset varies because the bar moves,
     and pinning the bar stops it moving. One constant beats a measurement
     kept in step by JavaScript.

     dvh where it is understood, vh as the fallback: on iOS a vh counts
     browser chrome that is not on screen, which is what the old clipping
     reports were.

     HEIGHT AND MAX-HEIGHT ARE BOTH SET, deliberately. The reveal animates
     max-height from 0, and height being full from the start is what lets
     the panel lay its content out at full height while max-height is still
     clipping it. Setting only height would give a panel that appears
     instantly; setting only max-height would give a full-height clip round
     content that stops after the last link. */
  .navmenu.open{
    height:calc(100vh - 72px);
    max-height:calc(100vh - 72px);
    overflow-y:auto;visibility:visible;transition-delay:0s,0s;
    overscroll-behavior:contain;
  }
  @supports (height:1dvh) {
    .navmenu.open{height:calc(100dvh - 72px);max-height:calc(100dvh - 72px)}
  }

  /* The bar is FIXED for as long as the drawer is open, which is what makes
     the drawer's fixed top:72px correct on every page and at every scroll
     position. 72px is .nav-in's height, the same constant :target's
     scroll-margin is built from.

     The announcement bar goes with it. It sits ABOVE the nav and does not
     stick, so at the top of a page it would otherwise be left showing in the
     72px the bar has moved up into. */
  html.nav-on .nav{position:fixed;top:0;left:0;right:0}
  html.nav-on .ann{visibility:hidden}

  /* min-height:100% so the column fills the panel even when the links do
     not, which is what gives .navmenu-foot something to be pushed to. */
  .navmenu .wrap{display:flex;flex-direction:column;padding-block:6px 24px;min-height:100%}
  .navmenu a{
    font-family:var(--mono);font-size:13px;letter-spacing:.14em;text-transform:uppercase;
    color:var(--on-ink-soft);padding-block:16px;border-bottom:1px solid var(--line-d);transition:color .15s;
  }
  /* Sub-items sit under Tours, indented and set in body type rather than the
     tracked mono of a nav label, so they read as destinations rather than as
     four more sections of the site. */
  .navmenu .navmenu-sub{padding-block:12px;padding-left:16px;
    border-left:2px solid rgba(217,142,43,.55)}
  .navmenu .navmenu-sub b{display:block;font-family:var(--body);font-size:15px;
    font-weight:500;color:var(--on-ink);letter-spacing:0;text-transform:none}
  .navmenu .navmenu-sub i{display:block;font-style:normal;font-size:10.5px;
    letter-spacing:.06em;color:var(--honey);margin-top:3px}
  /* The way out of the shortlist to the full eleven. Kept inside the amber
     rule so it still reads as part of Tours, but in the nav's own mono so it
     is plainly a link to a page and not a fifth departure. */
  /* The foot of the menu: account icon on the left, currency beside it.
     One row, and the icon carries no visible label -- the list above is
     the site's sections, and these two are controls. */
  /* margin-top:auto now the panel is full height: the controls belong at
     the foot of the screen rather than floating under the last link with
     an empty half-screen below them. The 18px stays as the minimum gap
     for the case where the links do fill the panel. */
  .navmenu-foot{display:flex;align-items:center;gap:18px;margin-top:auto;padding-top:18px}
  /* The picker used to be the last child of a COLUMN, where
     align-self:flex-end put it against the right edge and margin-top gave
     it air. In a row those mean something else entirely: align-self is the
     vertical axis, so it bottom-aligned, and the margin pushed it down.
     margin-left:auto is what "right" means in a row. Specificity of three
     classes, because .navmenu .curpick sets both and sits later in the
     file. */
  .navmenu .navmenu-foot .curpick{align-self:center;margin-top:0;margin-left:auto}
  /* .navmenu a gives every link in here a border and vertical padding,
     which is right in the list and wrong on a 44px icon in a row. */
  .navmenu .navmenu-acct{display:flex;align-items:center;justify-content:center;
    width:44px;height:44px;flex:none;padding-block:0;border-bottom:0;margin-left:-10px}
  .navmenu .navmenu-acct i{position:relative;display:block;width:19px;height:19px;flex:none}
  .navmenu .navmenu-acct i::before{content:"";position:absolute;left:50%;top:0;
    width:6px;height:6px;margin-left:-4px;border:1.5px solid currentColor;border-radius:50%}
  .navmenu .navmenu-acct i::after{content:"";position:absolute;left:50%;bottom:1px;
    width:13px;height:7px;margin-left:-7.5px;
    border:1.5px solid currentColor;border-bottom:0;border-radius:8px 8px 0 0}
  .navmenu .navmenu-all{font-family:var(--mono);font-size:11px;letter-spacing:.14em;
    text-transform:uppercase;color:var(--honey);padding-block:13px}
  /* Only the rule below the last link goes; it used to take the honey colour
     too, which made Contact look like a different kind of item from Gallery
     and About when it is just the last of the four. */
  .navmenu a:last-child{border-bottom:0}
  .navmenu a:hover,.navmenu a:focus-visible{color:var(--on-ink)}

  /* The currency picker inside the phone menu. Two things have to be undone.
     .navmenu a above dresses every link as a nav item -- 13px mono, 16px of
     vertical padding and a rule underneath -- and at identical specificity
     it beats .curpick a purely by sitting later in the file, so the chips
     came out oversized with a line under each. And the menu is a flex
     column, which stretches its children: the bordered group ran the whole
     width of the screen, which read as EUR growing to fill it. */
  /* Right-aligned, alone on its row. The links above it all start at the
     left margin, so sitting hard right is what stops it being read as a
     fifth section of the site. */
  .navmenu .curpick{align-self:flex-end;margin-top:20px}
  .navmenu .curpick a{font-size:11px;letter-spacing:.12em;padding:0 16px;
    min-height:44px;display:inline-flex;align-items:center;border-bottom:0}
  .navmenu .curpick a + a{border-left:1px solid var(--line-d)}
}

/* Narrow phones: the logo, the Reserve button and the new menu button
   do not all fit at 375px, and the Reserve button -- the thing the ads
   are paying for -- was the one being squashed. Tighten the spacing and
   step the logo down from 38px to 32px below 560px. Desktop is untouched. */
@media(max-width:560px){
  .nav-in{gap:12px}
  .nav .logo img{height:38px}
  .nav .btn-amber{padding:14px 14px;font-size:11px}
  .navtoggle{margin-left:0}
}

/* =================================================================
   Tour page
   -----------------------------------------------------------------
   The design reference covers the homepage only. Nothing here is a
   new visual idea -- every block reuses the reference's components
   (the spec strip, the dark section, the olive band, the bordered
   grid) so the tour page reads as the same site.
   ================================================================= */

.tour-hero{min-height:clamp(560px,78vh,820px)}
.tour-hero .d1{max-width:20ch;font-size:clamp(34px,5.4vw,74px)}
.tour-hero .lede{max-width:56ch}

/* spec strip sitting on the dark hero rather than on white */
.spec-dark{margin-top:clamp(24px,3vw,34px);border-color:var(--line-d);background:rgba(25,19,16,.42)}
.spec-dark div{border-right-color:var(--line-d)}
.spec-dark dd{color:var(--on-ink);font-size:clamp(15px,1.5vw,21px)}
.spec-dark dt{color:var(--on-ink-soft)}
.spec-dark dd s{color:var(--on-ink-soft)}
@media(max-width:520px){.spec-dark div:nth-child(-n+3){border-bottom-color:var(--line-d)}}

/* the at-a-glance strip reuses the marquee bar, without the travel */
/* The glance strip's links carry NO link styling, on Sampath's
   instruction: the cursor is the whole signal. Colour inherited so the
   strip still reads as one line of type rather than as three buttons. */
.marq-t a{color:inherit;text-decoration:none;cursor:pointer}
/* The strip is amber, so the site's amber focus ring vanished on it. */
.marq-t a:focus-visible{outline-color:var(--on-accent)}

.marq-static{width:100%;animation:none;flex-wrap:wrap;justify-content:center;padding:0;row-gap:0}
.marq-static span{font-size:13px;padding-inline:14px;gap:14px}
.marq-static span:last-child::after{display:none}
/* Four full-height lines on a phone, otherwise. */
@media(max-width:700px){
  .marq{padding:9px 0}
  .marq-static{gap:2px 0}
  .marq-static span{font-size:11.5px;padding-inline:9px;gap:9px;letter-spacing:.01em}
  .marq-static span::after{width:4px;height:4px}
}

/* intro + facts */
.tour-intro{display:grid;grid-template-columns:1.5fr 1fr;gap:clamp(24px,4vw,64px);align-items:start}
@media(max-width:900px){.tour-intro{grid-template-columns:1fr}}
.tour-para{margin-top:18px;max-width:64ch}
.tour-facts{border-top:2px solid var(--amber);background:var(--sand);position:sticky;top:var(--stickytop);border-radius:0 0 var(--r-card) var(--r-card);overflow:hidden}
@media(max-width:900px){.tour-facts{position:static}}
.tour-facts div{display:flex;gap:16px;padding:14px clamp(16px,2vw,22px);border-bottom:1px solid var(--line)}
.tour-facts div:last-child{border-bottom:0}
.tour-facts dt{font-family:var(--mono);font-size:10px;letter-spacing:.16em;text-transform:uppercase;color:var(--grey);flex:0 0 38%;padding-top:3px}
.tour-facts dd{font-size:15.5px;color:var(--prose-strong);flex:1}
/* Airport links. Without this they inherit a{color:inherit;text-decoration:none}
   and read as plain text -- same amber underline as the hotel links in
   .day-spec, so an external link looks the same wherever it appears. */
.tour-facts dd a{border-bottom:1px solid var(--amber)}

/* UPI payment screen. The QR is Barnowl's own Kotak code, so it carries no
   amount and no reference -- the caption below it has to, or a desktop rider
   scanning it sends the wrong sum against nothing. */
/* The UPI app chooser. Four names rather than one button, so the rider picks
   the app instead of the phone picking it for them. They wrap to two rows on a
   narrow screen and stay comfortably past the 44px touch target.

   Every one of these links is a deep link into a phone app. A desktop browser
   cannot follow any of them, so on a computer the buttons are hidden and the
   QR is the whole payment path. Same test the rest of the site uses for
   "this is a touch device": no hover, or a narrow screen. */
.upi-pay{display:none}
@media(hover:none),(max-width:760px){.upi-pay{display:block}}
/* Bank details are the desktop path, where no app link can be followed.
   Keyed on hover alone, with no width clause: a mouse means a computer,
   whatever size the window is. .upi-pay keeps its width clause as a safety
   net for any phone that misreports hover -- a rider on a phone losing the
   buttons is far worse than a narrow desktop window showing them. The two
   overlap in that one case rather than leaving a gap, which is the right way
   round for a payment screen. */
.upi-bank{display:none}
@media(hover:hover){.upi-bank{display:block}}
.upi-bank .kv{max-width:460px}
.upi-apps{display:flex;flex-wrap:wrap;gap:9px;margin-top:11px}
.upi-apps .btn{display:inline-flex;align-items:center;justify-content:center;gap:9px;padding:12px 18px}
/* The logo is a fixed square whatever the file's own proportions are, so one
   app supplying a wide wordmark cannot make its button taller than the rest.
   Buttons look right with no icons at all -- see upi_icon(). */
.upi-apps img{width:20px;height:20px;flex:none;object-fit:contain;display:block}
@media(max-width:420px){.upi-apps{gap:8px}.upi-apps .btn{flex:1 1 calc(50% - 4px);padding:12px 8px}}

.upi-qr{margin:24px 0 0;padding:clamp(16px,2vw,22px);background:var(--sand);
  border:1px solid var(--line);max-width:360px;border-radius:var(--r-card)}
/* White in both themes: a QR code has to be scannable, not themed. */
.upi-qr img{display:block;width:100%;height:auto;background:#fff}
.upi-qr figcaption{font-family:var(--mono);font-size:11.5px;line-height:1.6;
  letter-spacing:.03em;color:var(--prose);margin-top:14px}
.upi-qr strong{color:var(--ink);font-weight:600}
@media(max-width:560px){
  /* On a phone the deep-link button is the path that works; the code is a
     fallback, so it stops competing for the fold. */
  .upi-qr{max-width:260px}
}

/* the week, day by day -- one bar per day, height = metres climbed.
   Built from real text rather than an SVG so the day numbers, distances
   and place names stay legible and selectable at every width, and so the
   whole thing can turn into rows on a phone. */
.profile-sec{background:var(--sand)}
/* Short / long route toggle. Both readings are in the markup and CSS shows
   one, so switching is a class on the figure -- no text is rewritten, and the
   figures can never disagree with the bars because they came from the same
   render. Only appears where a tour's long option is genuinely longer. */
.week-toggle{display:inline-flex;gap:0;margin-bottom:14px;
  border:1px solid var(--line);border-radius:var(--r);overflow:hidden}
.week-toggle button{font-family:var(--mono);font-size:10.5px;letter-spacing:.16em;
  text-transform:uppercase;padding:9px 16px;background:none;color:var(--grey);
  border:0;cursor:pointer;transition:background .18s,color .18s}
.week-toggle button + button{border-left:1px solid var(--line)}
.week-toggle button:hover{color:var(--ink)}
.week-toggle button.on{background:var(--ink-surface);color:var(--on-ink)}
.week-toggle button:focus-visible{outline:2px solid var(--amber);outline-offset:-2px}
/* One class, on the section, because the two readings appear in two places --
   the heading totals and every day's figure -- and they must never disagree.
   Toggling anything narrower would let the heading say one route while the
   bars showed the other. */
.v-long{display:none}
.profile-sec.long .v-short{display:none}
.profile-sec.long .v-long{display:inline}
.profile-sec.long .wd-bar{height:calc(var(--pct-long) * 1%)}
.week{--track:clamp(150px,21vw,220px);--gut-l:56px;margin:clamp(20px,2.6vw,34px) 0 0}
.week-plot{position:relative;height:var(--track);margin-left:var(--gut-l)}
.week-line{position:absolute;left:0;right:0;height:0;border-top:1px solid var(--line)}
.week-line:first-of-type{border-top-style:dashed}
.week-line i{position:absolute;right:calc(100% + 11px);top:-.66em;font-style:normal;
  font-family:var(--mono);font-size:11px;letter-spacing:.06em;color:var(--grey);white-space:nowrap}
.week-unit{position:absolute;left:calc(var(--gut-l)*-1);bottom:calc(100% + 9px);
  font-family:var(--mono);font-size:10px;letter-spacing:.14em;text-transform:uppercase;color:var(--grey)}
.week-days{position:absolute;inset:0;z-index:1;display:grid;
  grid-template-columns:repeat(var(--n),1fr);gap:clamp(3px,.7vw,9px);
  list-style:none;margin:0;padding:0}
.wd{display:flex;flex-direction:column;justify-content:flex-end;min-width:0}
.wd-track{flex:1;display:flex;flex-direction:column;justify-content:flex-end;min-height:0}
.wd-m{flex:none;font-family:var(--mono);font-size:11px;font-weight:600;color:var(--ink);
  text-align:center;line-height:1;padding-bottom:5px;min-height:11px;white-space:nowrap}
/* Hidden on the desktop chart: the axis is already labelled "Metres climbed"
   and repeating the unit on every bar would just be noise. */
.wd-m i{display:none}
.wd-bar{width:100%;height:calc(var(--pct) * 1%);background:var(--amber);min-height:2px}
.wd-chip{width:100%;padding:5px 0;background:var(--olive-wash);color:var(--olive-ink);
  font-family:var(--mono);font-size:9px;letter-spacing:.12em;text-transform:uppercase;
  text-align:center;line-height:1;white-space:nowrap;overflow:hidden}
.week-legend{list-style:none;margin:0;padding:9px 0 0;margin-left:var(--gut-l);
  display:grid;grid-template-columns:repeat(var(--n),1fr);gap:clamp(3px,.7vw,9px);
  border-top:1.5px solid var(--ink);text-align:center}
.week-legend li{min-width:0}
.week-legend b{display:block;font-family:var(--mono);font-size:12px;font-weight:700;
  color:var(--ink);letter-spacing:.04em}
/* Direct child only. It used to be a descendant selector, which also caught
   the .v-short / .v-long spans nested inside and beat their display:none on
   specificity -- so the short view listed both distances, "92 km 126 km". */
.week-legend li > span{display:block;font-family:var(--mono);font-size:11px;color:var(--clay);margin-top:3px}

/* The bars grow in once, in step with the rest of the scroll reveals. */
@media(prefers-reduced-motion:no-preference){
  .wd-bar,.wd-chip{transform:scaleY(.001);transform-origin:bottom;
    transition:transform .9s cubic-bezier(.22,1,.36,1)}
  .wd-m{opacity:0;transition:opacity .5s ease .5s}
  .week.in .wd-bar,.week.in .wd-chip{transform:none}
  .week.in .wd-m{opacity:1}
  .wd:nth-child(2) .wd-bar,.wd:nth-child(2) .wd-chip{transition-delay:.05s}
  .wd:nth-child(3) .wd-bar,.wd:nth-child(3) .wd-chip{transition-delay:.1s}
  .wd:nth-child(4) .wd-bar,.wd:nth-child(4) .wd-chip{transition-delay:.15s}
  .wd:nth-child(5) .wd-bar,.wd:nth-child(5) .wd-chip{transition-delay:.2s}
  .wd:nth-child(6) .wd-bar,.wd:nth-child(6) .wd-chip{transition-delay:.25s}
  .wd:nth-child(7) .wd-bar,.wd:nth-child(7) .wd-chip{transition-delay:.3s}
  .wd:nth-child(8) .wd-bar,.wd:nth-child(8) .wd-chip{transition-delay:.35s}
  .wd:nth-child(9) .wd-bar,.wd:nth-child(9) .wd-chip{transition-delay:.4s}
  .wd:nth-child(10) .wd-bar,.wd:nth-child(10) .wd-chip{transition-delay:.45s}
  .wd:nth-child(n+11) .wd-bar,.wd:nth-child(n+11) .wd-chip{transition-delay:.5s}
}

/* On a phone eleven columns cannot hold a legible label, so the chart
   becomes one row per day and the bars run left to right instead. The
   day number and distance come from data- attributes because the legend
   below is a separate list, and duplicating it in the markup would make
   a screen reader read every day twice. */
@media(max-width:680px){
  .week{--gut-l:0px}
  .week-plot{height:auto}
  .week-line,.week-unit{display:none}
  .week-days{position:static;grid-template-columns:1fr;gap:0}
  .wd{flex-direction:row;align-items:center;gap:9px;padding:8px 0;
    border-bottom:1px solid var(--line)}
  .wd:last-child{border-bottom:0}
  .wd::before{content:"D" attr(data-n);flex:0 0 30px;
    font-family:var(--mono);font-size:11.5px;font-weight:700;color:var(--ink)}
  .wd::after{content:attr(data-km);flex:0 0 52px;text-align:right;
    font-family:var(--mono);font-size:11px;color:var(--clay)}
  .profile-sec.long .wd::after{content:attr(data-km-long)}
  /* On this layout the bars run left to right in a fixed 14px lane, so the
     alternative route lengthens them sideways. The desktop rule above changes
     their HEIGHT, which here made the rows different thicknesses. */
  .profile-sec.long .wd-bar{height:100%;width:calc(var(--pct-long) * 1%)}
  .wd-track{flex:1;flex-direction:row;align-items:center;justify-content:flex-start;
    height:14px;gap:8px}
  .wd-bar{order:1;height:100%;width:calc(var(--pct) * 1%);min-width:3px}
  /* margin-left:auto keeps the numbers in a column while the bars all
     start at the same left edge, so their lengths stay comparable. */
  .wd-m{order:2;flex:0 0 58px;margin-left:auto;min-height:0;padding:0;
    text-align:right;font-size:11px}
  /* The scale and its caption are gone on this layout, so each figure has to
     carry its own unit or the number means nothing. */
  .wd-m i{display:inline;font-style:normal;font-weight:400;color:var(--grey);margin-left:2px}
  .wd-chip{order:1;width:auto;padding:3px 9px;font-size:8.5px}
  .week-legend{position:absolute;width:1px;height:1px;overflow:hidden;
    clip-path:inset(50%);white-space:nowrap;padding:0;margin:0;border:0}
  @media(prefers-reduced-motion:no-preference){
    .wd-bar,.wd-chip{transform:scaleX(.001);transform-origin:left}
  }
}

/* itinerary */
@media(max-width:760px){.day{grid-template-columns:1fr;gap:12px}}
/* .day-no and .day-no .n were removed 3 Sep 2026: nothing on the site emits
   that class any more, so the rules were styling an element that no longer
   exists. Removed alongside a stylesheet change that already had to ship, so
   nobody re-downloads the file for dead CSS on its own. */
.restpill{display:inline-block;margin-top:10px;font-family:var(--mono);font-size:10px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--olive-ink);border:1px solid var(--olive-ink);padding:4px 8px}
.day-body>p{margin-top:14px;color:var(--prose);max-width:70ch;font-size:16.5px}
/* Borders that survive WRAPPING, which the first version did not.

   It was written for the four-item day spec on a tour page: one row, so a
   right border on every cell and none on the last was the whole job. The
   booking and admin screens then reused it with nine and eleven items,
   where it fell apart -- no horizontal rules between rows at all, and
   :last-child stripped the border from whichever cell happened to come
   last, which in a wrapped grid is a cell in the middle of a row.

   Every cell now draws its own right and bottom edge, and the negative
   margins pull the outermost of those under the container's own border,
   where overflow:hidden clips them. That is independent of how many items
   there are and how they fall, so the four-item case looks exactly as it
   did and a three-row one is finally square. */
.day-spec{display:grid;grid-template-columns:repeat(4,1fr);border:1px solid var(--line);
  margin:16px 0 4px;overflow:hidden;border-radius:var(--r-card)}
@media(max-width:620px){.day-spec{grid-template-columns:repeat(2,1fr)}}
.day-spec div{padding:11px 13px;margin:0 -1px -1px 0;
  border-right:1px solid var(--line);border-bottom:1px solid var(--line)}
.day-spec dt{font-family:var(--mono);font-size:10px;letter-spacing:.16em;text-transform:uppercase;color:var(--grey);margin-bottom:5px}
.day-spec dd{font-size:14.5px;font-weight:500;line-height:1.3}
.day-spec dd a{border-bottom:1px solid var(--amber)}
.day-hl{list-style:none;margin-top:18px;display:flex;flex-direction:column;gap:8px}
.day-hl li{position:relative;padding-left:22px;font-size:15.5px;color:var(--prose-strong)}
.day-hl li::before{content:"";position:absolute;left:0;top:9px;width:9px;height:1.5px;background:var(--amber)}

/* pricing */
.pricebox{margin-top:22px;border-top:1px solid var(--line-d)}
.pricebox div{display:flex;align-items:baseline;gap:16px;padding-block:13px;border-bottom:1px solid var(--line-d)}
.pricebox dt{font-family:var(--mono);font-size:11px;letter-spacing:.14em;text-transform:uppercase;color:var(--on-olive);flex:1}
.pricebox dd{font-family:var(--disp);font-weight:700;font-stretch:84%;font-size:24px;color:var(--on-ink)}
.depstatus{display:block;font-style:normal;font-family:var(--mono);font-size:10.5px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--honey);margin-top:5px}
/* A date that cannot be booked. Honey reads as an invitation from across the
   page, which is the wrong thing for the word CLOSED to be set in. */
.depstatus.shut{color:var(--on-olive)}

/* Route map. Lazily fetched as the reader reaches it, so it costs nothing on
   arrival -- the section sits below the fold on a page ads land on. */
/* White panel, because the section behind it is sand -- a sand map frame on a
   sand section had no edge at all. */
.routemap{margin:0;border:1px solid var(--line);background:var(--white);line-height:0}
.routemap iframe{display:block;width:100%;height:clamp(340px,52vw,560px);border:0}
/* Reserve the height before the src arrives, so nothing jumps when it loads. */
.routemap iframe:not([src]){background:var(--white)}

/* inclusions */
.inex{display:grid;grid-template-columns:1fr 1fr;gap:clamp(20px,2.6vw,38px);margin-top:clamp(26px,3.5vw,44px)}
@media(max-width:820px){.inex{grid-template-columns:1fr}}
.q-ex{border-top-color:var(--clay)}
.inex .d3{margin-bottom:16px}
.ticks{list-style:none;display:flex;flex-direction:column;gap:11px}
.ticks li{position:relative;padding-left:26px;font-size:16px;color:var(--prose-strong);line-height:1.5}
.ticks li::before{content:"✓";position:absolute;left:0;top:0;font-family:var(--mono);font-size:13px;color:var(--amber)}
.ticks-no li::before{content:"×";color:var(--clay);font-size:15px}

/* practical accordions */
.practical{border-top:1px solid var(--line)}
.pblock{border-bottom:1px solid var(--line)}
.pblock summary{cursor:pointer;list-style:none;padding-block:20px;display:flex;align-items:center;gap:14px;
  font-family:var(--disp);font-weight:700;font-stretch:84%;text-transform:uppercase;font-size:clamp(17px,1.9vw,21px)}
.pblock summary::-webkit-details-marker{display:none}
.pblock summary::after{content:"+";margin-left:auto;font-family:var(--mono);font-size:20px;color:var(--amber);
  font-weight:400;transition:transform .3s cubic-bezier(.22,1,.36,1)}
.pblock[open] summary::after{transform:rotate(45deg)}
.pblock summary:hover{color:var(--clay)}
.pbody{padding-bottom:24px;max-width:74ch}
.pbody p{margin-bottom:12px;color:var(--prose);font-size:16.5px}
.pbody p:last-child{margin-bottom:0}
.pbullet{position:relative;padding-left:22px}
.pbullet::before{content:"";position:absolute;left:0;top:11px;width:9px;height:1.5px;background:var(--amber)}

/* photograph grid */
/* the "also running" cards reuse .cellx as links */
a.cellx:hover h3{color:var(--honey)}
a.cellx .no{color:var(--honey)}

/* =================================================================
   Content pages
   ================================================================= */

.phero{background:var(--ink-surface);color:var(--on-ink);padding-block:clamp(48px,7vw,96px) clamp(40px,5.5vw,72px)}
.phero .d1{max-width:18ch;font-size:clamp(36px,6vw,80px)}
.phero .lede{color:var(--on-ink-prose);max-width:58ch;margin-top:20px}
.phero .kicker{color:var(--on-ink-mute);margin-bottom:16px}

/* long-form prose */
.prose{max-width:72ch}
.prose h2{font-family:var(--disp);font-weight:800;font-stretch:82%;text-transform:uppercase;
  font-size:clamp(22px,2.6vw,32px);line-height:1;margin:clamp(34px,4vw,52px) 0 16px}
.prose h2:first-child{margin-top:0}
.prose h3{font-family:var(--disp);font-weight:700;font-stretch:84%;text-transform:uppercase;
  font-size:19px;margin:30px 0 10px}
.prose p{margin-bottom:15px;color:var(--prose);font-size:16.5px}
.prose ul{list-style:none;margin:0 0 18px}
.prose li{position:relative;padding-left:24px;margin-bottom:10px;color:var(--prose);font-size:16.5px}
.prose li::before{content:"";position:absolute;left:0;top:11px;width:10px;height:1.5px;background:var(--amber)}
.prose a{border-bottom:1px solid var(--amber)}

/* ---------------------------------------------------------------
   HOVER ON A TEXT LINK. Sampath, 2 Sep 2026: they did not change at all.

   The site has one text-link look, an amber underline, set in thirteen
   places, and not one of them had a :hover. .tlink is that look given a
   name, so the seven inline style="border-bottom..." anchors that had
   grown around the templates stop being their own little copies.

   WHY currentColor AND NOT A COLOUR. These links sit on four different
   grounds, and it was measured rather than guessed:

       white prose     clay 6.07 : 1     honey 1.85 : 1
       sand panels     clay 5.39         honey 1.65
       ink sections    clay 3.03         honey 9.93
       the olive band  clay 1.69         honey 5.53

   Clay is right on the two light grounds and fails on the two dark ones;
   honey is the exact mirror. No single colour serves both, and enumerating
   the dark sections is the mistake .btn-out already made once, when the
   list missed .dark and drew a dark border on a dark ground.

   currentColor sidesteps the whole question: the link's own text colour is
   legible on its ground by definition, so the underline snaps from amber to
   full contrast wherever it is, in either theme, with nothing to keep in
   step. .linkish and .bk-out already reach for var(--ink) for the same
   reason; this is that idea without the light-ground assumption baked in.

   Colour only, no thickening: a wider border reflows the line. */
.tlink{border-bottom:1px solid var(--amber)}
.prose a,.tlink,.fineprint a,.gh-more a,
.tour-facts dd a,.day-spec dd a,.bk-files a,.bk-who a,
.adm-lead-contact a{transition:border-color .18s,color .18s}
.prose a:hover,.tlink:hover,.fineprint a:hover,.gh-more a:hover,
.tour-facts dd a:hover,.day-spec dd a:hover,.bk-files a:hover,.bk-who a:hover,
.adm-lead-contact a:hover{border-bottom-color:currentColor}
/* Keyboard users get the same signal as the mouse, on top of the focus ring. */
.prose a:focus-visible,.tlink:focus-visible,.fineprint a:focus-visible,.gh-more a:focus-visible,
.tour-facts dd a:focus-visible,.day-spec dd a:focus-visible,.bk-files a:focus-visible,
.bk-who a:focus-visible,
.adm-lead-contact a:focus-visible{border-bottom-color:currentColor}

/* ONE PLACE NEEDS MORE THAN THE UNDERLINE. A link in a table heading inherits
   .dtable th's grey, so amber going to that grey is a change of 1.81:1 and
   barely reads. Measured, not guessed.

   The text lifts to --ink here and nowhere else, because .dtable th is the one
   of these grounds that is provably safe for it: its background is always
   --sand, and --sand and --ink flip together with the theme, so the pair holds
   in both. Everywhere else keeps the currentColor underline alone rather than
   assuming a ground. */
.dtable th a:hover,.dtable th a:focus-visible{color:var(--ink)}
.prose strong{font-weight:600;color:var(--ink)}

/* data tables (payment schedule, difficulty levels) */
.dtable{width:100%;border-collapse:collapse;margin:22px 0 8px;font-size:15.5px}
.dtable th,.dtable td{border:1px solid var(--line);padding:12px 14px;text-align:left;vertical-align:top}
.dtable th{font-family:var(--mono);font-size:10px;letter-spacing:.16em;text-transform:uppercase;
  color:var(--grey);font-weight:400;background:var(--sand)}
.dtable td:first-child{font-family:var(--mono);font-size:13px;white-space:nowrap}
.tablewrap{overflow-x:auto}
/* Inside a blog post a table is followed by prose, not by fine print as on
   /payments-cancellations/, so the 8px under it put the next paragraph
   almost on the bottom border. Seen on the gearing post's two tables, 1 Oct
   2026; the Vietnam comparison had the same gap. */
.longread .dtable{margin-bottom:26px}

/* key/value callout, e.g. bank details */
/* Same panel as .tour-facts and .pside: amber rule, sand, rounded below. */
.kv{border-top:2px solid var(--amber);background:var(--sand);margin:22px 0;border-radius:0 0 var(--r-card) var(--r-card);overflow:hidden}
.kv div{display:flex;gap:16px;padding:12px 18px;border-bottom:1px solid var(--line)}
.kv div:last-child{border-bottom:0}
.kv dt{font-family:var(--mono);font-size:10px;letter-spacing:.16em;text-transform:uppercase;
  color:var(--grey);flex:0 0 40%;padding-top:3px}
.kv dd{font-size:15.5px;font-weight:500;flex:1}

/* two-column content page */
.pcols{display:grid;grid-template-columns:1fr 320px;gap:clamp(28px,5vw,72px);align-items:start}
/* A GRID ITEM'S DEFAULT MINIMUM IS ITS CONTENT, NOT ZERO, which is what gave
   /payments-cancellations/ a horizontal scroll on a 360px phone: the schedule
   and refund tables are wider than that, .tablewrap wraps them in
   overflow-x:auto so they can scroll inside themselves, and the track ignored
   that and sized itself to the table anyway. The page then ran 12px wide and
   the whole thing scrolled sideways instead of just the table.

   min-width:0 lets the track shrink and hands the scrolling back to
   .tablewrap, which is what it was put there to do. Measured 1 Sep 2026:
   at 1280px every .pcols child is the same size and position to the pixel
   with and without this, so it only touches the case that was broken. */
.pcols > *{min-width:0}
@media(max-width:900px){.pcols{grid-template-columns:1fr}}
.pside{border-top:2px solid var(--amber);background:var(--sand);padding:clamp(20px,2.4vw,28px);position:sticky;top:var(--stickytop);border-radius:0 0 var(--r-card) var(--r-card)}
@media(max-width:900px){.pside{position:static}}
.pside h3{font-family:var(--disp);font-weight:700;font-stretch:84%;text-transform:uppercase;font-size:19px;line-height:1.05;margin-bottom:14px}
.pside ul{list-style:none;display:flex;flex-direction:column;gap:10px;font-size:15px}
/* A postal address is one thing, not a list of four. The sidebar's 10px gap
   is right for four separate links and wrong for the lines of an address,
   which should sit as they would on an envelope. */
.pside ul.addr{gap:2px}

/* A TOUR'S OPTIONAL EXTENSION, inside the itinerary below the tour's last
   day (Costa Brava & Girona's gravel days, 4 Nov 2026). A hairline and space
   above it, so it reads as a further, separate part rather than Day 10 of
   the same trip. The photograph stands on its own in the prose column, so
   it takes the card radius itself. */
.ext{margin-top:clamp(48px,6vw,80px);padding-top:clamp(32px,4vw,48px);border-top:1px solid var(--line)}
.ext .pcols{margin-bottom:clamp(24px,3vw,36px)}
.ext-photo{margin-top:22px;border-radius:var(--r-card);overflow:hidden}
.ext-photo img{display:block;width:100%;height:auto}

/* THE LEGAL CONTACT BLOCK, at the foot of the three policy pages.

   overflow-wrap because the email address is a 27 character string with
   nothing to break on, and the .kv label column leaves it under 200px on a
   360px phone. It pushed the whole grid 29px wide and gave the page a
   horizontal scroll, which the quality floor does not allow. "anywhere"
   rather than "break-all": it breaks only when a word genuinely does not fit,
   so the address lines above it still wrap at their spaces. */
.legal-kv dd{overflow-wrap:anywhere}
.pside a{color:var(--prose)}
.pside a:hover{color:var(--clay)}

/* archive cards on the tours index */
.archive{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(18px,2.4vw,32px);margin-top:clamp(26px,3.5vw,44px)}
@media(max-width:900px){.archive{grid-template-columns:repeat(2,1fr)}}
@media(max-width:560px){.archive{grid-template-columns:1fr}}
.acard{background:var(--white);display:flex;flex-direction:column;transition:transform .4s cubic-bezier(.22,1,.36,1),box-shadow .4s;border-radius:var(--r-card);overflow:hidden}
.acard:hover{transform:translateY(-6px);box-shadow:0 18px 44px rgba(25,19,16,.09)}
.ashot{aspect-ratio:3/2;overflow:hidden;background:var(--sand-2)}
.ashot img{transition:transform .8s cubic-bezier(.22,1,.36,1)}
.acard:hover .ashot img{transform:scale(1.05)}
.abody{padding:20px 22px 24px;display:flex;flex-direction:column;flex:1}
.abody .d3{margin:8px 0 10px;font-size:20px}
.ameta{font-family:var(--mono);font-size:12px;color:var(--grey);letter-spacing:.03em;margin-bottom:16px}
.abody .go{margin-top:auto;margin-left:0}

/* team */
.team{display:flex;flex-direction:column;gap:1px;background:var(--line-d);
  border:1px solid var(--line-d);margin-top:clamp(26px,3.5vw,44px)}
.member{background:var(--ink-surface);display:grid;grid-template-columns:180px 1fr;gap:clamp(18px,3vw,38px);
  padding:clamp(20px,2.6vw,32px);transition:background .3s}
.member:hover{background:var(--ink-surface-2)}
.mphoto{aspect-ratio:1;overflow:hidden;background:var(--ink-surface-2);border-radius:var(--r-card)}
.mphoto img{filter:saturate(.9)}
.mbody .d3{color:var(--on-ink)}
.mrole{font-family:var(--mono);font-size:10.5px;letter-spacing:.16em;text-transform:uppercase;
  color:var(--amber);margin:6px 0 12px}
.mbody p{color:var(--on-ink-prose);font-size:16px;line-height:1.6}

/* forms */
.eform{margin-top:26px;max-width:66ch}
.frow{display:grid;grid-template-columns:1fr 1fr;gap:18px}
@media(max-width:620px){.frow{grid-template-columns:1fr}}
.field{margin-bottom:18px;display:flex;flex-direction:column}
.field label{font-family:var(--mono);font-size:10.5px;letter-spacing:.16em;text-transform:uppercase;
  color:var(--grey);margin-bottom:8px}
.field label span{color:var(--clay);margin-left:6px}
.field input,.field select,.field textarea{
  font-family:var(--body);font-size:16px;color:var(--ink);background:var(--white);
  border:1px solid var(--line);padding:13px 14px;border-radius:var(--r);width:100%;
  transition:border-color .18s,box-shadow .18s;
  /* iOS Safari sizes input[type=date] from its own content and that intrinsic
     width outranks width:100%, so the field pushes the page sideways on an
     iPhone while looking fine everywhere else. These two let it shrink. The
     native picker is untouched -- no appearance reset, which would take the
     iOS date UI with it. */
  min-width:0;
  max-width:100%;
}
/* Every single-line control is the same height, taken from --field-h
   rather than from whatever the browser makes of its own content. The
   line-height is that height less the padding and borders, so the text
   fills the content box exactly and sits centred -- a text input centres
   its own text, but a date field with appearance:none does not. */
.field input,.field select{
  height:var(--field-h);
  line-height:calc(var(--field-h) - 28px);
}
/* The date field, and only the date field.

   iOS Safari draws input[type=date] with native chrome sized from its own
   content, and that intrinsic width beats width:100%, min-width:0 and
   max-width:100% alike -- the box simply runs past the right edge of the
   phone and takes the page with it. It looks correct in every desktop
   browser, which is why measuring there found nothing.

   appearance:none makes it lay out as an ordinary box. Tapping it still
   opens the native date wheel: appearance governs how the closed control is
   drawn, not what happens when it is tapped. The value is a shadow element
   of its own, which iOS centres, so it is aligned back to the left to match
   every other field. */
.field input[type="date"]{-webkit-appearance:none;appearance:none}
.field input[type="date"]::-webkit-date-and-time-value{text-align:left;margin:0}

/* Selects.

   Safari on macOS draws a select with its own native metrics and ignores
   the vertical padding above, so Gender and "Tour you're interested in"
   came out visibly shorter than the text inputs around them. Chrome does
   honour the padding, which is why it looked right when measured here and
   wrong on the actual machine. appearance:none stops the browser drawing
   the control at all, so --field-h applies to a select exactly as it does
   to an input, in every browser.

   That also removes the native chevron, so we draw one. The right padding
   clears it; without that a long tour name would run underneath. */
.field select{
  -webkit-appearance:none;appearance:none;
  background-image:var(--caret);
  background-repeat:no-repeat;
  background-position:right 14px center;
  background-size:12px 8px;
  padding-right:38px;
}

.field textarea{resize:vertical;min-height:130px}
.field input:focus,.field select:focus,.field textarea:focus{
  outline:none;border-color:var(--amber);box-shadow:0 0 0 3px rgba(217,142,43,.16)}
.eform button{border:0;cursor:pointer;margin-top:6px}
.fineprint{font-family:var(--mono);font-size:11px;color:var(--grey);margin-top:16px;letter-spacing:.03em}
.fineprint a{border-bottom:1px solid var(--line)}
/* The honeypot: still in the DOM and fillable by bots, but clipped rather
   than pushed off-screen, because a negative offset can widen the scrollable
   area on some browsers. */
.hp{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}

/* PayPal checkout. The buttons themselves are PayPal's own iframe and
   cannot be restyled, so the job here is to give them a container that
   sits in our layout rather than fighting it. Capped at the width of a
   form field so they do not stretch across the column. */
/* PAYPAL'S BUTTONS ARE AN IFRAME IT STYLES ITSELF, and it gives that iframe
   a z-index of its own choosing -- high enough to sit over the sticky nav,
   which is what it did. We cannot restyle something inside a cross-origin
   frame, so the box it lands in is made a stacking context instead: whatever
   z-index PayPal sets is then resolved INSIDE this box and cannot climb above
   anything outside it.

   isolation does the job on its own; position and z-index are the same idea
   spelled the older way, for anything that does not know the property. */
.paypal-box{max-width:420px;margin-top:20px;min-height:52px;
  isolation:isolate;position:relative;z-index:0;
  background:var(--paypal-surface);padding:12px;border-radius:var(--r-card)}
/* HOW MUCH TO PAY: deposit, the first 50%, or the tour in full.

   The switch is CSS only. Every amount and every UPI deep link for all
   three is rendered by PHP and this shows one set, the same bargain the
   week chart's Short/Long toggle makes. It matters more here: a upi://
   link carries the amount inside it, so building them in JavaScript would
   put a second copy of upi_query() in the browser, and a payment link that
   disagrees with the figure beside it is the one bug this screen must not
   have.

   The radios are visually hidden but NOT display:none -- they still take
   focus and still carry the value into the UTR post. .payopt sits before
   .paywrap in the markup because these are sibling selectors; moving the
   inputs inside the wrapper stops all of this working while looking
   entirely reasonable. */
.payopt{position:absolute;width:1px;height:1px;margin:-1px;padding:0;
  border:0;clip-path:inset(50%);overflow:hidden;white-space:nowrap}
.payamt,.payfor{display:none}
#plan-deposit:checked ~ .paywrap .payamt[data-plan="deposit"],
#plan-first:checked   ~ .paywrap .payamt[data-plan="first"],
#plan-full:checked    ~ .paywrap .payamt[data-plan="full"]{display:inline}
#plan-deposit:checked ~ .paywrap .payfor[data-plan="deposit"],
#plan-first:checked   ~ .paywrap .payfor[data-plan="first"],
#plan-full:checked    ~ .paywrap .payfor[data-plan="full"]{display:block}

/* THE THREE WAYS TO PAY, IN TABS.

   Radios and CSS, so the panels cannot get out of step with the tab that
   is lit. The inputs sit before .paytabs because these are sibling
   selectors; moving them inside stops all of this working.

   UPI APPS IS NOT OFFERED ON A DESKTOP: a computer cannot follow a upi://
   link, so every one of those buttons would be dead.

   THE DEFAULT IS THE QR, EVERYWHERE, and that is deliberate. It is the one
   choice that is right on every device with no script and no remapping --
   which the first version of this did, lighting the wrong tab in a way
   that took a while to see. A phone then gets the apps tab preselected by
   the small script on the page, the same bargain the week chart makes:
   PHP renders every panel and script only moves which one is showing. With
   no script the rider lands on the QR and taps a tab, which is coherent
   rather than clever. */
.paytab-r{position:absolute;width:1px;height:1px;margin:-1px;padding:0;
  border:0;clip-path:inset(50%);overflow:hidden;white-space:nowrap}
.paytabs{margin-top:24px}
.paytab-list{display:flex;flex-wrap:wrap;gap:8px;
  border-bottom:1px solid var(--line);padding-bottom:12px;margin-bottom:20px}
/* Same chip as .gf. min-height stays at 44px here where it does not on the
   filter chips: this is the control a rider taps on a payment screen, and
   the quality floor asks for 44px on touch targets. The compactness comes
   from the type and the horizontal padding instead. */
.paytab{font-family:var(--mono);font-size:13px;letter-spacing:.01em;
  padding:10px 14px;min-height:44px;
  display:inline-flex;align-items:center;cursor:pointer;
  border:0;border-radius:var(--r);color:var(--ink-2);
  background:var(--sand-2);transition:background .18s,color .18s}
.paytab:hover{background:var(--line);color:var(--ink)}
.paypanel{display:none}

/* One rule per tab, and nothing conditional about it.
   'card' is CCAvenue, added 1 Sep 2026 and last in the list because it is the
   only one that costs the rider anything. */
#tab-apps:checked ~ .paytabs .paypanel[data-tab="apps"],
#tab-qr:checked   ~ .paytabs .paypanel[data-tab="qr"],
#tab-bank:checked ~ .paytabs .paypanel[data-tab="bank"],
#tab-card:checked ~ .paytabs .paypanel[data-tab="card"]{display:block}
#tab-apps:checked ~ .paytabs .paytab[data-tab="apps"],
#tab-qr:checked   ~ .paytabs .paytab[data-tab="qr"],
#tab-bank:checked ~ .paytabs .paytab[data-tab="bank"],
#tab-card:checked ~ .paytabs .paytab[data-tab="card"]{
  background:var(--ink-surface);color:var(--on-ink)}
#tab-apps:focus-visible ~ .paytabs .paytab[data-tab="apps"],
#tab-qr:focus-visible   ~ .paytabs .paytab[data-tab="qr"],
#tab-bank:focus-visible ~ .paytabs .paytab[data-tab="bank"],
#tab-card:focus-visible ~ .paytabs .paytab[data-tab="card"]{
  outline:3px solid var(--amber);outline-offset:2px}

/* The two a balance agreed in another currency is settled by: cash at the
   agreed figure, or the gateway with its own charge on top. Written out the
   same way as the three above rather than folded in with them -- the whole
   component works by naming each tab, and a clever selector that covered
   both sets would be the one thing here nobody could read. */
#tab-cash:checked ~ .paytabs .paypanel[data-tab="cash"],
#tab-gw:checked   ~ .paytabs .paypanel[data-tab="gw"]{display:block}
#tab-cash:checked ~ .paytabs .paytab[data-tab="cash"],
#tab-gw:checked   ~ .paytabs .paytab[data-tab="gw"]{
  background:var(--ink-surface);color:var(--on-ink)}
#tab-cash:focus-visible ~ .paytabs .paytab[data-tab="cash"],
#tab-gw:focus-visible   ~ .paytabs .paytab[data-tab="gw"]{
  outline:3px solid var(--amber);outline-offset:2px}

/* REPORTING A REFERENCE IS NOT FOR THE CARD TAB. A card payment records
   itself the moment CCAvenue confirms it, so the "tell us the UTR" block below
   the tabs is hidden while that tab is selected. Sampath's instruction,
   1 Sep 2026.

   :has() rather than a plain sibling selector because the radios sit inside a
   wrapper on both screens and the block sits outside it: on /reserve/ that
   wrapper is .paywrap, on /booking/ it is .bk-pay-block. Named out rather than
   left as a bare :has(), which would match every ancestor up to <html>.

   If :has() were ever unavailable the block simply shows, which is exactly
   what it did before this rule existed. */
.paywrap:has(#tab-card:checked) ~ .tellus,
.bk-pay-block:has(#tab-card:checked) ~ .tellus{display:none}

/* The card panel's button needed air: the line above it explains what the
   extra 2.5% is, and the two were running together. */
.paycard-go{margin-top:22px}

/* The apps tab exists only where a deep link can be followed. Same test
   .upi-pay already used, so "can this device open a UPI app" is answered
   the same way in both places. */
.paytab[data-tab="apps"]{display:none}
@media(hover:none),(max-width:760px){
  .paytab[data-tab="apps"]{display:inline-flex}
}

/* Inside a panel the tab decides what shows, so the old device rules on
   these two must not also have a say. Scoped to .paypanel, so booking.php
   keeps the behaviour it was written with. */
.paypanel .upi-pay,.paypanel .upi-bank{display:block}
.paypanel .upi-qr{margin-top:0}
.upi-id{max-width:460px;margin-top:18px}

/* The schedule, folded shut: open, it is the longest thing on the screen
   and it sits between a rider who came to pay and the box they pay with. */
/* The "What you pay, and when" control on the reserve page. Same button as
   the tour page's payment schedule -- .payplan-open carries the look -- so
   this only has to place it. */
.payplan-ask{margin-top:24px;border-top:1px solid var(--line);padding-top:18px}
.payplan-ask .payplan-open{min-height:44px}

.payhow{margin:22px 0 26px}
.payhow-q{font-family:var(--mono);font-size:10.5px;letter-spacing:.16em;
  text-transform:uppercase;color:var(--grey);margin-bottom:12px}
.payhow-opt{display:flex;flex-wrap:wrap;gap:2px 11px;align-items:baseline;
  border:1px solid var(--line);border-radius:var(--r);padding:13px 15px;
  margin-bottom:9px;cursor:pointer;min-height:44px;
  transition:border-color .18s,background .18s}
.payhow-opt:hover{border-color:var(--amber);background:var(--sand)}
.payhow-opt b{font-family:var(--disp);font-weight:800;font-stretch:82%;
  font-size:19px;letter-spacing:-.005em}
.payhow-opt>span{font-size:15.5px;line-height:1.5}
.payhow-opt .fine{flex:1 1 100%;margin:0}

/* The chosen one, and the focused one. The radio is hidden, so without
   these a keyboard user has nothing at all to go on. */
#plan-deposit:checked ~ .paywrap .payhow-opt[for="plan-deposit"],
#plan-first:checked   ~ .paywrap .payhow-opt[for="plan-first"],
#plan-full:checked    ~ .paywrap .payhow-opt[for="plan-full"]{
  border-color:var(--amber);background:var(--sand);box-shadow:inset 0 0 0 1px var(--amber)}
#plan-deposit:focus-visible ~ .paywrap .payhow-opt[for="plan-deposit"],
#plan-first:focus-visible   ~ .paywrap .payhow-opt[for="plan-first"],
#plan-full:focus-visible    ~ .paywrap .payhow-opt[for="plan-full"]{
  outline:3px solid var(--amber);outline-offset:2px}

/* The not-found block, shared by 404.php and the tour and post 404s. */
.nf-lede{max-width:52ch}
.nf-acts{display:flex;flex-wrap:wrap;gap:12px;margin-top:28px}

.notice{border-top:3px solid var(--amber);background:var(--sand);padding:20px 22px;margin-bottom:30px;border-radius:0 0 var(--r-card) var(--r-card)}
.notice-bad{border-top-color:var(--clay)}
/* Good news takes the olive rule, the same mark .depconf uses for "this is
   settled". The class was on every confirmation and styled by nothing. */
.notice-ok{border-top-color:var(--olive-ink)}
.notice p{margin-top:8px;color:var(--prose)}

/* gallery */
.gfilter{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:22px}
/* TABS AND FILTER CHIPS ARE FILLED, COMPACT AND IN SENTENCE CASE.
   Sampath's instruction, 31 Aug 2026, from a reference screenshot: a
   background instead of a border, simple padding so they stay compact, and
   no capitals. One chip idiom shared by the gallery filters, the tours
   filters, the admin tabs and the admin status filters, so "the tabs" means
   the same thing on a customer page and an admin one.

   THE TRACKING WENT WITH THE CAPITALS. Letter-spacing on this site exists to
   open up uppercase mono; at .14em on sentence case it reads as a fault
   rather than a style. Dropping both is what makes the chip narrow enough to
   call compact, more than the padding does.

   THE TEXT HAD TO DARKEN, and that is not taste. It was --grey, which passes
   on the white page these chips used to sit on directly. Measured against a
   filled --sand-2 chip it is 3.97:1, under the 4.5 minimum. --ink-2 on
   --sand-2 is 13.75:1. Selected stays --ink with white on it, 18.4:1. Do not
   put --grey back on a filled chip.

   .paytab and .dtab below follow the same three rules. */
.gf{font-family:var(--mono);font-size:13px;letter-spacing:.01em;
  padding:8px 13px;border:0;background:var(--sand-2);color:var(--ink-2);
  transition:background .18s,color .18s;border-radius:var(--r)}
/* The count beside a filter label. .55 measured 3.58:1 once the chip had a
   background behind it, so it is .7 -- still secondary, and legible. */
.gf span{opacity:.7;margin-left:5px}

/* Photo credit under a gallery. Mono and quiet, like every other label on
   the site -- it is an acknowledgement, not a headline. The link takes the
   clay used for links elsewhere and underlines on hover so it is plainly
   clickable without shouting. */
.gcredit{font-family:var(--mono);font-size:11px;letter-spacing:.1em;
  text-transform:uppercase;color:var(--grey);margin:-8px 0 22px}
.gcredit[hidden]{display:none}
.gcredit a{color:var(--clay);border-bottom:1px solid transparent;transition:border-color .15s}
.gcredit a:hover{border-bottom-color:var(--clay)}
/* On a tour page it sits under the section heading rather than a filter
   bar, so it needs space above it instead of the negative pull. */
.gcredit-tour{margin:14px 0 0}
.sec.dark .gcredit,.phero .gcredit{color:var(--on-ink-mute)}
.sec.dark .gcredit a,.phero .gcredit a{color:var(--honey)}
/* Hover deepens the fill rather than lighting a border, since there is no
   border to light any more. */
.gf:hover{background:var(--line);color:var(--ink)}
.gf.on{background:var(--ink-surface);color:var(--on-ink)}
.gf.on span{opacity:.7}
.gcount{font-family:var(--mono);font-size:11.5px;letter-spacing:.06em;color:var(--grey);margin-bottom:20px}

/* The tours filter. Reuses .gf from the gallery, so the two filters on the
   site look and behave like one control rather than two inventions. Two
   labelled rows instead of the gallery's single strip, because there are
   two axes and an unlabelled mix of "Europe" and "Advanced" would read as
   one list of unrelated words. */
/* [hidden] only hides an element that has no display of its own, and both
   cards set one: .tour is display:block and .acard is display:flex. Without
   these two lines the filter sets the attribute correctly and every tour
   stays on screen, which is exactly what shipped. Four other components in
   this stylesheet already carry the same guard -- .gcredit, .lb, .gh and
   .quotes-nav -- and it is the first thing to check when something "filters"
   but nothing moves. The sections are plain <section>s with no display of
   their own, but guarded too so a later layout change cannot reopen this. */
.tour[hidden],.acard[hidden]{display:none}
[data-sec-running][hidden],[data-sec-archive][hidden],[data-sec-empty][hidden]{display:none}

/* /booking/ -- a rider's own record. Reuses .day-spec, .dtable, .notice
   and .field so it looks like the rest of the site rather than a portal
   bolted on the side. */
.bk-spec{margin-top:clamp(24px,3vw,36px)}
.bk-h{margin-top:clamp(28px,3.5vw,44px)}
.bk-form{margin-top:clamp(20px,2.5vw,30px);max-width:420px}
.bk-form .btn{margin-top:18px}
.bk-files{margin-top:14px;display:flex;flex-direction:column;gap:10px}
.bk-files li{display:flex;flex-wrap:wrap;align-items:baseline;gap:10px;
  border-bottom:1px solid var(--line);padding-bottom:10px}
.bk-files a{border-bottom:1px solid var(--amber)}
.bk-files .fine{margin:0}
/* A UTR or a PayPal capture id: long, and meant to be compared character
   by character against a bank statement, so it gets the mono face. */
.bk-txn{font-family:var(--mono);font-size:12px;word-break:break-all}
/* The booking page's payment block, where the amount is a BALANCE rather
   than the reserve screen's Rs 5,000 deposit. The SAME .paytab component,
   with one tab different, and both differences follow from that amount.

   THE QR TAB IS DESKTOP ONLY HERE, where the reserve screen keeps it on
   every device. On the phone you would be paying from, a code you have to
   scan with that same phone is furniture. The apps tab is already touch
   only from the shared rule above, so a phone offers apps and bank, and a
   desktop offers QR and bank.

   The account is on EVERY device, which .paypanel .upi-bank above already
   does: a balance can run past a rider's per-transaction UPI cap and the
   published terms say the balance goes by bank transfer, so hiding it on a
   phone leaves them with no route that works.

   BANK TRANSFER IS THEREFORE THE DEFAULT in booking.php's markup, not the
   QR. It is the one panel present on every device, which is exactly the
   reasoning that makes the QR the reserve screen's default: with no
   JavaScript, every rider lands on a panel that works. */
@media(hover:none),(max-width:760px){
  .bk-pay-block .paytab[data-tab="qr"]{display:none}
}

/* Admin. Reuses .dtable, .field, .gf and .notice so it is recognisably the
   same site, not a bolted-on tool with its own visual language. The shell
   itself -- top bar, cards, tiles, tables -- is the block at the END of this
   file, added 22 Oct 2026. */
.adm-filter{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:14px}
.adm-search{display:flex;flex-wrap:wrap;gap:10px;margin-bottom:22px}
.adm-search input{flex:1;min-width:220px;height:var(--field-h);
  border:1px solid var(--line);border-radius:var(--r);padding:0 14px;
  font-family:var(--body);font-size:15px;background:var(--white);color:var(--ink)}

/* The enquiries filter bar: search, a date range and a tour, in one form.

   Scoped to .adm-filterbar throughout, NOT to .adm-search, because the
   bookings tab uses .adm-search too and none of this should reach it. */
.adm-filterbar{align-items:flex-end}
.adm-nf{display:flex;flex-direction:column;gap:5px;flex:0 0 auto;min-width:0}
.adm-nf>span{font-family:var(--mono);font-size:10.5px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--grey)}

/* EVERY control in this bar is wrapped in a label, including the search
   box. Without its own label the search sat a label's height higher than
   the three beside it, because a flex item with less content starts at the
   top of the row. Giving it one is what puts all four on a line, and it
   says what the box is into the bargain. */
.adm-filterbar .adm-nf input,.adm-filterbar .adm-nf select{
  flex:none;width:100%;min-width:0;max-width:100%;height:var(--field-h);
  border:1px solid var(--line);border-radius:var(--r);padding:0 12px;
  font-family:var(--body);font-size:14.5px;background:var(--white);color:var(--ink)}

.adm-nf-date{flex:0 0 165px}
.adm-nf-grow{flex:1 1 220px}

/* The button sits in the row with the fields, so it takes their height.
   --field-h exists so that every single-line control in a row agrees, and
   a 42px button beside 49px fields is the disagreement it is there to
   stop. Scoped to this bar: .btn's own height is the approved design and
   it carries the Reserve button on every public page. */
.adm-filterbar>.btn{min-height:var(--field-h);display:inline-flex;
  align-items:center;justify-content:center}

/* The date fields need the SAME treatment .field input[type=date] gets,
   and for the same reason: iOS Safari draws them with native chrome sized
   from their own content, and that intrinsic width beats width:100%,
   min-width:0 and max-width:100% alike. The box runs past the right edge
   of the phone and drags the page with it -- which is exactly what it did
   here, with From and To overlapping, because this rule was scoped to
   .field and these are not .field. Measured on a desktop it looked fine,
   which is how it shipped. */
.adm-filterbar .adm-nf input[type="date"]{-webkit-appearance:none;appearance:none}
.adm-filterbar .adm-nf input[type="date"]::-webkit-date-and-time-value{text-align:left;margin:0}

/* appearance:none for the same reason .field select has it: Safari draws a
   native select from its own metrics and ignores the height, so this one
   would sit shorter than the date fields beside it. Taking the control off
   the browser also takes its chevron, so we draw ours. */
.adm-filterbar .adm-nf select{
  -webkit-appearance:none;appearance:none;
  background-image:var(--caret);background-repeat:no-repeat;
  background-position:right 12px center;background-size:12px 8px;padding-right:34px}

/* The bookings pager: the count, the two buttons, and the page size.
   space-between so the count sits left and the size sits right with the
   buttons between them, and it collapses to stacked rows on a phone. */
.adm-pager{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;
  gap:12px 18px;margin-top:18px;padding-top:16px;border-top:1px solid var(--line)}
.adm-pager p{margin:0}
.adm-pager-nav{display:flex;align-items:center;gap:10px}
.adm-pager-nav .btn{margin-top:0}
.adm-pager-of{white-space:nowrap}
.adm-pager-per{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.adm-pager-per .gf{padding:6px 12px}
/* Previous and Next at the ends of the list. Kept in the flow as inert
   text rather than removed, so the row does not jump about as you page. */
.adm-pager .is-off{opacity:.4;pointer-events:none}

@media(max-width:620px){
  /* Stacked and centred: side by side these three wrap into a mess at
     360px, and the two buttons are what the thumb is reaching for. */
  .adm-pager{justify-content:center;text-align:center}
  .adm-pager-nav{order:-1;width:100%;justify-content:center}
  .adm-pager-nav .btn{flex:1 1 0;min-height:44px}
  .adm-pager-count,.adm-pager-per{width:100%;justify-content:center}
}

.adm-export{display:flex;flex-wrap:wrap;align-items:center;gap:12px;margin:-6px 0 22px}
.adm-export .btn{margin-top:0}
.adm-export .fine{margin:0}

@media(max-width:620px){
  /* The two dates share a row and everything else takes its own. The 5px
     is half the 10px gap, so two of them fill the row exactly. */
  .adm-nf-date{flex:1 1 calc(50% - 5px)}
  .adm-nf-grow{flex:1 1 100%}
  .adm-filterbar>.btn{flex:1 1 100%}
}
.adm-table td{vertical-align:top}
.adm-table .fine{margin:2px 0 0}
.adm-st{display:inline-block;font-family:var(--mono);font-size:10.5px;
  letter-spacing:.1em;text-transform:uppercase;padding:4px 9px;border-radius:var(--r);
  border:1px solid var(--line);white-space:nowrap}
/* Tinted from the palette rather than typed as pale hexes, so the chips
   follow the theme: the old fills were light-ground colours and sat as
   bright patches on the dark panel. Olive is the site's "settled" mark and
   amber its "look at this"; both measure over 5:1 on either ground. */
.st-ok{background:var(--olive-wash);border-color:color-mix(in srgb, var(--olive-ink) 45%, transparent);color:var(--olive-ink)}
.st-warn{background:color-mix(in srgb, var(--amber) 18%, transparent);border-color:color-mix(in srgb, var(--amber) 50%, transparent);color:var(--clay)}
.st-wait{color:var(--grey)}
/* The payment reminders switch on a booking. The whole row is the button, a
   real submit with role="switch", so the label is as much a target as the
   track. No slide: pressing it posts and the page comes back in the new
   state, so there is nothing for a transition to animate. The knob is
   --on-ink rather than --white because --white goes dark in dark mode. */
.adm-switch{display:flex;align-items:center;justify-content:space-between;gap:16px;
  width:100%;padding:0;border:0;background:none;color:inherit;font:inherit;
  text-align:left;cursor:pointer}
.adm-switch .d3{margin:0}
.adm-switch-track{position:relative;flex:0 0 auto;width:46px;height:26px;
  border-radius:13px;background:var(--line)}
.adm-switch-track::after{content:"";position:absolute;top:3px;left:3px;
  width:20px;height:20px;border-radius:50%;background:var(--on-ink)}
.adm-switch[aria-checked="true"] .adm-switch-track{background:var(--amber)}
.adm-switch[aria-checked="true"] .adm-switch-track::after{left:23px}
.adm-switch:focus-visible{outline-offset:6px;border-radius:var(--r)}
/* The same responsive field row on the admin screens and on the rider's
   own payment form. One definition, two names, because a rule called
   .adm- has no business being the layout on a customer-facing page. */
/* ROW GAP BIGGER THAN THE COLUMN GAP, for a row that WRAPS. */
.adm-row,.bk-tell-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:24px 14px}
/* AND ABOVE A ROW, WHATEVER PRECEDES IT, which is the gap that was actually
   too tight. The admin forms are several sibling .adm-row blocks, not one grid
   that wraps, so the grid's own row-gap never applied between them: they sat
   flush, and a row's LABEL ended up nearer the input above it than the control
   it names. Fixing the gap alone did nothing, which is what the first attempt
   at this got wrong.

   IT WAS THEN WRITTEN AS .adm-row + .adm-row, WHICH WAS TOO NARROW, and
   Sampath reported the same complaint a second time on 2 Sep 2026 against
   "Record a payment". A row does not only ever follow another row: it follows
   the sentence explaining the form just as often, and .fine carries a
   margin-TOP and no margin-bottom, so the explanation sat directly on top of
   the first label with nothing between them.

   :not(:first-child) rather than naming what may precede it. The thing above
   a row is a paragraph here, a heading there, and a hidden input in the forms
   that carry a CSRF token, and enumerating those is how this gets reported a
   third time. A row that genuinely opens its container still gets nothing. */
.adm-row:not(:first-child){margin-top:24px}
/* A voided booking. Struck through and muted, the same language the
   filter uses for a combination that would return nothing. */
.st-void{opacity:.6;text-decoration:line-through}
/* The removal block. Marked out, but not shouting: this is a tool the
   owner uses, not a warning to a visitor. No red anywhere -- the palette
   does not have one, deliberately. */
.adm-danger{border:1px solid var(--line);background:var(--white)}
/* The two folded blocks on a booking: "Edit these details" and "Record a
   refund". Same summary, because they are the same kind of thing -- an
   action you take now and then, kept out of the way of the ones you take
   every day. */
.adm-edit form{margin-top:16px}
.adm-edit .field{margin-bottom:0}
/* The refund block's own contents need the breathing room the heading used
   to give them, now that the heading is the summary. */
.adm-fold>*:not(summary):first-of-type{margin-top:14px}
.adm-fold form{margin-top:16px}
.adm-purge .fine{margin-top:10px}
.btn-danger{background:var(--clay);border-color:var(--clay);color:var(--on-ink)}
.btn-danger:hover{background:var(--ink-surface);border-color:var(--ink)}
/* The bulk bar. Sticks to the top of the viewport while you scroll a long
   list, because the enquiry you want and the button are otherwise far
   apart. */
.adm-bulk{position:sticky;top:78px;z-index:6;display:flex;flex-wrap:wrap;gap:10px;
  align-items:center;margin-bottom:12px;padding:12px 14px;background:var(--ink-surface);
  color:var(--on-ink);border-radius:var(--r)}
.adm-bulk[hidden]{display:none}
.adm-bulk span{font-family:var(--mono);font-size:11.5px;letter-spacing:.1em;text-transform:uppercase}
.adm-bulk input[type=text]{height:38px;border:1px solid rgba(246,241,232,.3);border-radius:var(--r);
  padding:0 12px;background:transparent;color:var(--on-ink);font-family:var(--mono);font-size:12.5px}
.adm-bulk input[type=text]::placeholder{color:rgba(246,241,232,.62)}
.adm-bulk .btn{margin-top:0;padding:9px 15px}
.adm-pick{display:inline-flex;align-items:center;gap:7px;margin-bottom:6px;cursor:pointer}
.adm-pick input{width:16px;height:16px;accent-color:var(--amber)}
.adm-pick .fine{margin:0}
.adm-undo{display:flex;flex-wrap:wrap;gap:8px;align-items:center}
.adm-undo input{height:38px;border:1px solid var(--line);border-radius:var(--r);padding:0 10px;
  font-family:var(--mono);font-size:12px;max-width:130px}
.adm-undo .btn{margin-top:0;padding:9px 14px}
.adm-import-help{max-width:none;margin-bottom:20px}
.adm-import-help code{font-family:var(--mono);font-size:12.5px;background:var(--sand);padding:1px 5px;border-radius:3px}
.adm-import label{display:block;font-family:var(--mono);font-size:11px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--grey);margin-bottom:8px}
.adm-import textarea{width:100%;border:1px solid var(--line);border-radius:var(--r);
  padding:12px 14px;font-family:var(--mono);font-size:12.5px;line-height:1.6;
  background:var(--white);color:var(--ink);white-space:pre;overflow-x:auto}
.adm-import .acts{margin-top:14px;gap:10px}
.adm-problems{margin:10px 0 0;padding-left:18px;font-size:14.5px;line-height:1.6}
.adm-problems li{margin-bottom:4px}
/* "Then tell us the reference": the rider's own UTR box, at the foot of
   the payment panel. Set off from the paying instructions above it with a
   rule, because it is a different act -- that block is how to send money,
   this is telling us it has been sent. */
.bk-tell-h{margin-top:clamp(24px,3vw,34px);padding-top:clamp(20px,2.6vw,28px);
  border-top:1px solid var(--line);font-size:clamp(16px,1.7vw,20px)}
.bk-tell{margin-top:16px}
.bk-tell .field{margin-bottom:0}
.bk-tell .btn{margin-top:18px}
/* The two ways into /booking/: a reference, or a code by email. Side by
   side where there is room, stacked on a phone. The reference form keeps
   the amber button because it is still the fastest way in for a rider
   holding one; signing in is the outlined one beside it. */
.bk-ways{display:grid;gap:clamp(20px,3vw,34px);margin-top:clamp(20px,3vw,30px)}
.bk-way{padding:clamp(18px,2.4vw,26px);background:var(--sand);border-radius:var(--r-card)}
.bk-way .d3{margin-bottom:10px}
.bk-way .fine{margin-bottom:14px}
.bk-way .btn{margin-top:16px}
/* Side by side, and the same height.

   align-items:start let each card be only as tall as its own content, so
   the sign-in one -- which carries a sentence the reference one does not --
   always hung lower than its neighbour. Removing it lets the default,
   stretch, give both the height of the grid row.

   That is the whole fix. Making the card a flex column to bottom-align the
   two buttons as well was tried and put back: a flex container stops
   margins collapsing, so .bk-form's own margin-top stopped merging with
   the heading's margin-bottom and every gap inside both cards grew by
   about 24px. Equal heights was the ask; the rest was worth less than the
   spacing it disturbed. */
@media(min-width:800px){.bk-ways{grid-template-columns:1fr 1fr}}

/* The code field. Wide, tracked and centred, so six digits read as six
   digits and a mistyped one is obvious. */
.bk-code{margin-top:clamp(18px,2.4vw,26px);max-width:340px}
.bk-code input{font-family:var(--mono);font-size:24px;letter-spacing:.34em;
  text-align:center;padding-left:10px}
/* Who is signed in, and the way out. The sign-out is a real form so it can
   be a POST -- a link that signs you out is a link anything can follow. */
.bk-who{display:flex;flex-wrap:wrap;align-items:baseline;gap:4px 8px;
  margin:0 0 16px;font-size:14px}
.bk-who a{border-bottom:1px solid var(--amber)}
.bk-out{display:inline}
.bk-out button{background:none;border:0;padding:0;cursor:pointer;color:inherit;
  font:inherit;border-bottom:1px solid var(--amber)}
.bk-out button:hover{color:var(--ink)}
@media(max-width:620px){.bk-out button{min-height:44px}}
/* "Make the next payment", folded away.

   The summary is the button: amber, the same shape and weight as .btn, so
   it reads as the thing to press rather than as a heading with a triangle
   beside it. The default marker is removed and replaced with a chevron
   that turns, because the native triangle sits outside the button box and
   breaks the shape. */
.bk-pay{margin-top:clamp(26px,3.2vw,40px)}
.bk-pay>summary{list-style:none;cursor:pointer;display:flex;flex-wrap:wrap;
  align-items:baseline;gap:4px 14px;padding:16px 46px 16px 20px;position:relative;
  background:var(--amber);color:var(--on-accent);border-radius:var(--r-card);
  transition:background .18s ease}
.bk-pay>summary::-webkit-details-marker{display:none}
.bk-pay>summary:hover{background:var(--honey)}
.bk-pay>summary:focus-visible{outline:2px solid var(--ink);outline-offset:3px}
.bk-pay-lede{font-family:var(--mono);font-size:11.5px;letter-spacing:.16em;
  text-transform:uppercase;font-weight:600}
.bk-pay-sum{font-size:15px;line-height:1.4}
/* The chevron. Two borders rotated, so there is no image to load and it
   inherits the text colour on any ground. */
.bk-pay>summary::after{content:"";position:absolute;right:20px;top:50%;
  width:9px;height:9px;margin-top:-6px;border-right:2px solid currentColor;
  border-bottom:2px solid currentColor;transform:rotate(45deg);
  transition:transform .18s ease}
.bk-pay[open]>summary::after{transform:rotate(-135deg);margin-top:-2px}
.bk-pay[open]>summary{border-radius:var(--r-card) var(--r-card) 0 0}
.bk-pay-body{border:1px solid var(--line);border-top:0;
  border-radius:0 0 var(--r-card) var(--r-card);padding:clamp(18px,2.4vw,28px)}
.bk-pay-body>*:first-child{margin-top:0}
@media(prefers-reduced-motion:reduce){
  .bk-pay>summary,.bk-pay>summary::after{transition:none}
}
@media(max-width:560px){
  .bk-pay>summary{padding:14px 40px 14px 16px}
  .bk-pay-sum{width:100%}
}
/* DATA TABLES ON A PHONE.

   Measured on an iPhone 17, 402px wide: the departure roster laid out at
   715px inside a 366px box, so 349px of it -- half the table -- sat behind
   a sideways scroll with nothing to signpost it. The columns that
   disappeared were Received, Still owed and Needs checking, which are the
   three the screen exists to answer. The rider's own payment table did the
   same to its Reference and Status columns.

   So below 620px these stop being tables and become one card per row, each
   cell labelled from the heading it lost. Nothing is hidden and nothing
   scrolls sideways. Applied by an opt-in class, because a two-column table
   like the refund schedule on /payments-cancellations/ is perfectly
   readable as a table and stacking it would only make it taller. */
@media (max-width:620px){
  .dtable-stack,.dtable-stack tbody,.dtable-stack tr,.dtable-stack td{display:block;width:auto}
  /* The headings still exist for a screen reader; they are just not drawn,
     because each cell now carries its own label. */
  .dtable-stack thead{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%)}
  .dtable-stack{border-collapse:separate;margin:16px 0 8px;font-size:15px}
  .dtable-stack tr{border:1px solid var(--line);border-radius:var(--r-card);
    background:var(--white);padding:2px 14px 6px;margin-bottom:12px}
  /* :first-child is named explicitly because .dtable td:first-child sets
     nowrap and a mono 13px, and it OUT-RANKS a plain .dtable-stack td --
     two class-level selectors against one. So the first cell kept nowrap
     and a long tour name ran straight out of the card: "Tuscany: Cycling
     Through Wine Countr" with the rest off the screen. */
  .dtable-stack td,.dtable-stack td:first-child{border:0;border-bottom:1px solid var(--line);
    padding:10px 0;display:flex;gap:16px;align-items:baseline;justify-content:space-between;
    text-align:right;white-space:normal;overflow-wrap:anywhere;
    font-family:var(--body);font-size:15px}
  .dtable-stack td:last-child{border-bottom:0}
  .dtable-stack td::before{content:attr(data-label);flex:0 0 auto;text-align:left;
    font-family:var(--mono);font-size:10px;letter-spacing:.16em;text-transform:uppercase;
    color:var(--grey);line-height:1.9}
  /* A cell with nothing in it is noise once it is a labelled row of its
     own, so the markup leaves those out and this catches the rest. */
  .dtable-stack td:empty{display:none}
  .dtable-stack td .fine{margin:0}
  .dtable-stack .bk-txn{font-size:12px}
  /* A cell holding a figure AND a dates line, which is the price column on
     the India hub. As flex items in a row the long "email me when they are
     set" link squeezed the rupee figure into a column three characters wide
     and it wrapped a character at a time. The figure keeps its line and the
     dates take a line of their own underneath, right-aligned like the rest. */
  .dtable-stack td{flex-wrap:wrap}
  .dtable-stack .ih-price{white-space:nowrap}
  .dtable-stack .ih-dates{flex:1 1 100%;margin-top:2px}
  /* The row that names the thing reads as its heading, not as a field. */
  /* The row that names the thing. Also has to beat td:first-child, which
     is why the font is restated rather than left to inherit. */
  .dtable-stack td[data-lead],.dtable-stack td[data-lead]:first-child{display:block;
    text-align:left;padding-top:12px;font-family:var(--body);font-weight:600;font-size:16px;
    white-space:normal;overflow-wrap:anywhere}
  .dtable-stack td[data-lead]::before{display:block;margin-bottom:3px}
  /* Nothing left to scroll once the rows are stacked. */
  .tablewrap:has(>.dtable-stack){overflow-x:visible}
  /* Tap targets. Apple asks for 44px; these measured 36px on the tabs and
     17px on the disclosure summaries, which is a link-sized target on a
     control that opens half a screen. */
  /* .dtab and the customer-side chips join the admin tabs here rather than
     carrying the height everywhere. Compact is the point on a desktop; a
     finger is not. .dtab measured 33px once the chips were made compact, and
     .gf on the gallery and tours filters is the same chip, so all of them
     are raised on a small screen. .paytab keeps its 44px unconditionally: it
     is the control on a payment screen, not somewhere to save nine pixels. */
  .adm-filter .gf,.gfilter .gf,.tfilter .gf,.dtab{
    min-height:44px;display:inline-flex;align-items:center}
  .adm-edit>summary,.adm-fold>summary,.adm-purge>summary,.adm-emails>summary,.adm-lapsed>summary{
    min-height:44px;display:flex;align-items:center}
  /* Copy and Open measured 41px. Scoped to this row rather than raising
     .btn everywhere: that height is the approved design and it carries the
     Reserve button on every public page. */
  .adm-link-row .btn{min-height:44px}
  /* And the rider's own "I have paid" button, which is the most important
     thing to be able to hit on this page. Scoped for the same reason. */
  .bk-tell button{min-height:44px}
  /* The export button, measured at 40px on a 375px screen. Scoped to this
     row for the same reason as the ones above: .btn's own height is the
     approved design. The FILTER button is not listed here -- it already
     takes --field-h from the rule above, which is 49px, and naming it
     again here would quietly shrink it back to 44. */
  .adm-export .btn{min-height:44px}
  /* The three ways into /booking/ -- reference, email, code -- measured
     41px, 43px and 41px. Same scoped treatment: .btn's own height is the
     approved design and carries Reserve on every public page. */
  .bk-form .btn{min-height:44px}
  /* And the add-a-booking form's own buttons, 43px. Same scoping rule. */
  .adm-manual .btn{min-height:44px}
}
/* Money going the other way. Muted rather than coloured: the palette has
   no red, deliberately, and a refund is not an error. The word in the
   status column does the work; this only stops it reading as a payment at
   a glance down a column of figures. */
.dtable tr.pay-out td{color:var(--grey)}
.dtable tr.pay-out td:first-child{color:var(--grey)}
/* The rider's own link, ready to send. The field is readonly and selects
   on click, so the link is copyable by hand whatever the clipboard API
   does. */
.adm-link{margin:0 0 clamp(18px,2.4vw,26px)}
.adm-link label{display:block;margin:0 0 7px;font-family:var(--mono);font-size:10px;
  letter-spacing:.16em;text-transform:uppercase;color:var(--grey)}
.adm-link-row{display:flex;flex-wrap:wrap;gap:8px}
.adm-link-url{flex:1 1 320px;min-width:0;height:var(--field-h);
  border:1px solid var(--line);border-radius:var(--r);padding:0 12px;
  font-family:var(--mono);font-size:12.5px;background:var(--white);color:var(--ink)}
.adm-link-row .btn{margin-top:0;display:inline-flex;align-items:center;gap:8px;white-space:nowrap}
/* Two overlapping rectangles, drawn in borders so there is no image to
   load and it takes the button's own colour on any ground. */
.adm-copy-icon{position:relative;display:inline-block;width:12px;height:12px;flex:0 0 auto}
.adm-copy-icon::before,.adm-copy-icon::after{content:"";position:absolute;
  border:1.5px solid currentColor;border-radius:2px}
.adm-copy-icon::before{left:0;top:0;width:8px;height:8px}
.adm-copy-icon::after{right:0;bottom:0;width:8px;height:8px;background:var(--white)}
.adm-copy.is-done{border-color:var(--olive);color:var(--olive)}
.adm-copy.is-done .adm-copy-icon{display:none}
@media(max-width:560px){.adm-link-url{flex:1 1 100%}}
/* The "email the rider" tick box. Full width under the fields it belongs
   to, so it reads as part of the action rather than as another field. */
.adm-tell{display:flex;gap:10px;align-items:flex-start;margin-top:16px;cursor:pointer}
.adm-tell input{width:16px;height:16px;margin-top:3px;flex:0 0 auto;accent-color:var(--amber)}
.adm-tell input:disabled{accent-color:var(--grey)}
.adm-tell > span{font-size:14.5px;line-height:1.5}
.adm-tell .fine{display:block;margin:2px 0 0}
.adm-tell:has(input:disabled){cursor:default}
/* The addresses for one departure, ready to paste. A plain textarea: it
   selects on click, it wraps, and it needs no script. */
.adm-emails{margin-top:18px}
.adm-emails textarea{width:100%;border:1px solid var(--line);border-radius:var(--r);
  padding:12px 14px;font-family:var(--mono);font-size:12.5px;line-height:1.7;
  background:var(--white);color:var(--ink);resize:vertical}
/* The mail log. Monospace and scrollable, because these lines are machine
   output and wrapping them costs more than a scrollbar does. */
.adm-log{margin-top:14px;border:1px solid var(--line);border-radius:var(--r);
  background:var(--white);padding:12px 14px;max-height:340px;overflow:auto}
.adm-log div{font-family:var(--mono);font-size:11.5px;line-height:1.8;
  white-space:pre;color:var(--prose)}
.adm-log div+div{border-top:1px solid var(--sand-2)}
/* Add a booking: the everyday single entry, with the bulk paste folded
   underneath. Reuses .adm-row for the field grid and .adm-fold for the
   disclosure, so it is the same furniture as the rest of the panel. */
.adm-import-lede{max-width:62ch;margin-bottom:clamp(16px,2vw,22px)}
.adm-manual .adm-row{margin-bottom:14px}
.adm-manual .field{margin-bottom:0}
.adm-manual .acts{display:flex;flex-wrap:wrap;gap:10px;margin-top:clamp(18px,2.4vw,26px)}
.adm-manual .acts .btn{margin-top:0}
.adm-paste{margin-top:clamp(26px,3.2vw,40px)}
.adm-paste .adm-import-help{margin-top:14px}
/* One enquiry. A card rather than a table row, because the message is the
   point of it and a message does not fit in a cell. */
.adm-lead{border:1px solid var(--line);border-radius:var(--r-card);
  padding:clamp(14px,1.8vw,20px);margin-bottom:12px;background:var(--white)}
.adm-lead-head{display:flex;flex-wrap:wrap;gap:8px 22px;justify-content:space-between;align-items:flex-start}
.adm-lead-head .d3{font-size:clamp(16px,1.6vw,19px)}
.adm-lead-head .fine{margin:4px 0 0}
.adm-lead-contact{text-align:right}
.adm-lead-contact a{border-bottom:1px solid var(--amber)}
.adm-lead-msg{margin-top:12px;font-size:15px;line-height:1.6;white-space:pre-line}
.adm-lead-note{margin-top:10px;border-left:3px solid var(--amber);padding-left:12px}
.adm-lead-form{display:flex;flex-wrap:wrap;gap:10px;margin-top:14px;align-items:center}
.adm-lead-form select,.adm-lead-form input{height:var(--field-h);border:1px solid var(--line);
  border-radius:var(--r);padding:0 12px;font-family:var(--body);font-size:14.5px;
  background:var(--white);color:var(--ink)}
.adm-lead-form input{flex:1;min-width:180px}
.adm-lead-form .btn{margin-top:0}
@media(max-width:560px){.adm-lead-contact{text-align:left}}

.tfilter{display:flex;flex-direction:column;gap:10px;margin-bottom:18px}
.tfrow{display:flex;flex-wrap:wrap;align-items:center;gap:8px}
.tflabel{font-family:var(--mono);font-size:11px;letter-spacing:.16em;text-transform:uppercase;
  color:var(--grey);min-width:62px}
/* A combination that would return nothing. Greyed and unpressable rather
   than removed: options that vanish as you press others make the control
   feel broken, and the count already says why it is dead. */
.gf.off{opacity:.38;pointer-events:none;text-decoration:line-through}
/* The filter is a control for the list under it, not a section of its own,
   and both are white. A full section gap between them therefore reads as
   the page having run out rather than as a division: it measured 121px
   from "Showing 10 of 10" to "On sale now", and on a 900px screen it put
   the first tour below the fold. The lead-in under the hero is trimmed for
   the same reason.

   The archive below keeps its full padding, because the ground changes to
   sand there and the space is doing work. */
.tours-filter-sec{padding-top:clamp(30px,3.2vw,46px);padding-bottom:0}
.tours-filter-sec + [data-sec-running],
[data-sec-running] + [data-sec-empty]{padding-top:clamp(22px,2.2vw,32px)}
@media(max-width:560px){
  .tflabel{min-width:0;width:100%;margin-bottom:-2px}
}
/* Both groups on one line where there is room for them, which halves the
   control's height: 91px stacked against 40px in a row.

   Dropdowns were the other way to get one line and were rejected. With
   three options each they turn one click into two, and they would hide
   the two things this filter says without being touched: the count on
   every option, and the struck-through zero that stops a rider walking
   into Europe plus Advanced. A <select> would also need JavaScript, where
   every option here is a real link today -- and desktop Safari draws
   selects from its own metrics, which is the bug --field-h exists to work
   around.

   1040px, not 1000: the two groups need 881px of the content column, and
   a 1000px window leaves about 940px. Too close to wrap the moment a
   count goes from one digit to two. */
@media(min-width:1040px){
  .tfilter{flex-direction:row;flex-wrap:wrap;align-items:center;gap:10px 30px}
  .tfilter .tflabel{min-width:0}
}

/* THE PHOTOGRAPH GRID, shared by /gallery/ and a tour page.

   Columns rather than a grid, so every photograph shows WHOLE. The tour
   page used to crop its own to 3:2 in a separate .shots grid, which threw
   away the top of a climb or the end of a bridge; Sampath asked for the
   gallery page's treatment in both places.

   THE GAP IS THE TOUR PAGE'S 2px, also his call, which makes this a
   mosaic rather than a set of cards. So the radius goes with it: the note
   in CLAUDE.md about rounding tiles applies here for the same reason --
   rounding each at this gap breaks the wall into blobs. A photograph in a
   CARD still takes the card's radius; this is not a card.

   Two columns on a phone, not one. */
.gg{columns:3;column-gap:2px}
@media(max-width:900px){.gg{columns:2}}
@media(max-width:560px){.gg{columns:2;column-gap:2px}}
/* Only the top margin the tour page's section needs; /gallery/ sets its
   own spacing above the grid. */
.gg-inline{margin-top:clamp(24px,3vw,40px)}
.gcell{break-inside:avoid;margin:0 0 2px;position:relative;background:var(--sand-2);overflow:hidden}
.gcell img{width:100%;height:auto;object-fit:contain;display:block;
  transition:transform .8s cubic-bezier(.22,1,.36,1);
  /* Part of the wash below, and the half of it that does the real work:
     colour taken out is what compresses a blown-out beach and a saturated
     jungle into one set. Warmth alone only tints.

     .78 chosen from a proof sheet of six settings, 30 Aug 2026. If the
     grid ever reads flat rather than calm -- most likely at phone size,
     where the tiles are small -- this is the number to lift, to about .82,
     rather than the wash below. */
  filter:saturate(.78) contrast(1.02)}
.gcell:hover img{transform:scale(1.04)}

/* A SINGLE WARM WASH OVER EVERY PHOTOGRAPH IN A GRID.

   Sampath asked for one calm, consistent feel across the tours. Clay at
   soft-light rather than a flat tint: soft-light leaves the darks dark and
   the highlights bright and only pulls the mid-tones towards the palette,
   so a photograph is still itself, just of a piece with the others.

   IT IS ONLY ON THE GRID. The lightbox builds its own .lb element on the
   body and never carries .gcell, so opening a photograph shows the file as
   it was taken. That is the point of the wash being here and not on the
   image itself.

   pointer-events:none so it never sits between a reader and .gopen, and
   z-index:1 so it stays under the caption -- washing the caption text
   would only make it harder to read. */
.gcell::after{content:"";position:absolute;inset:0;z-index:1;pointer-events:none;
  background:var(--clay);mix-blend-mode:soft-light;opacity:.58}
.gcell figcaption{position:absolute;left:0;right:0;bottom:0;z-index:3;pointer-events:none;padding:22px 14px 12px;color:var(--on-ink);
  font-size:13.5px;line-height:1.4;opacity:0;transform:translateY(6px);transition:.35s cubic-bezier(.22,1,.36,1);
  background:linear-gradient(180deg,transparent,rgba(25,19,16,.88))}
.gcell:hover figcaption,.gcell:focus-within figcaption{opacity:1;transform:none}

/* blog index */
.posts{display:grid;grid-template-columns:1fr 1fr;gap:clamp(20px,2.6vw,38px)}
@media(max-width:820px){.posts{grid-template-columns:1fr}}
.post{background:var(--white);border-top:3px solid var(--amber);display:flex;flex-direction:column;
  border-radius:0 0 var(--r-card) var(--r-card);overflow:hidden;
  transition:transform .4s cubic-bezier(.22,1,.36,1),box-shadow .4s}
.post:hover{transform:translateY(-6px);box-shadow:0 18px 44px rgba(25,19,16,.09)}
.pshot{aspect-ratio:16/9;overflow:hidden;background:var(--sand-2)}
.pshot img{transition:transform .8s cubic-bezier(.22,1,.36,1)}
.post:hover .pshot img{transform:scale(1.05)}
.post .pbody{padding:22px 24px 26px;display:flex;flex-direction:column;flex:1}
.post .d3{margin:10px 0 8px}
.pstrap{font-family:var(--mono);font-size:11.5px;letter-spacing:.1em;text-transform:uppercase;
  color:var(--clay);margin-bottom:12px}
.post p{color:var(--prose);font-size:16px}
.post .go{margin-top:auto;margin-left:0;padding-top:16px}
/* .post is display:flex, which beats the hidden attribute, so without this
   the blog filter sets it and every card stays on screen. Same guard as
   .tour[hidden] and .acard[hidden]. */
.post[hidden]{display:none}
/* The excerpt, held to three lines. A diary's excerpt is its first
   paragraph and ran to nine lines in a narrow card, which set the height of
   its whole row. */
.pex{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3;line-clamp:3;overflow:hidden}

/* long-form post */
.phero-post .d1{font-size:clamp(30px,4.6vw,60px);max-width:22ch}
/* THE MEASURE. .prose is 72ch, and a "ch" is the width of a zero, which in
   Plex Sans is a good deal wider than the average letter: measured on 1 Oct
   2026, a post's lines ran 91 to 103 characters at 1280px and wider, where
   60 to 80 is what reads comfortably. 600px brings them to about 75. Tables,
   the film and the comparison sit on the same measure, so the column has one
   right edge. A phone is narrower than this already and is unaffected. */
.longread{max-width:600px}
/* A post's headings are sentences, and at a reading width they wrap to two
   lines, which at .prose h2's flat 1 touched. 1.08, the same re-tuning the
   display headings had on 1 Sep 2026; a step smaller as well, since the
   column is narrower than a policy page's. Only in a post: the policy pages'
   headings are two or three words and are left exactly as they were. */
.longread h2{font-size:clamp(21px,2.2vw,27px);line-height:1.08;scroll-margin-top:calc(var(--navh) + 20px)}
.longread p{font-size:17.5px;line-height:1.75;margin-bottom:20px}
/* The few words in bold that open a checklist line. A <b> inherited the
   paragraph's grey, so the label and the sentence after it differed only in
   weight; in ink it is the thing the eye lands on down a list. */
.longread p b{font-weight:600;color:var(--ink)}
.longread p:first-child::first-letter{font-family:var(--disp);font-weight:800;font-stretch:82%;
  font-size:3.6em;line-height:.82;float:left;margin:4px 10px 0 0;color:var(--amber)}
/* A day's photographs among the words, two to a row in the reading column,
   and a rider's own account set off by a rule, both added 6 Oct 2026 for the
   Tuscany diary. The account's first paragraph is a first-child too, and
   would otherwise take the drop cap meant for the article's opening. */
.gg.gg-day{columns:2;column-gap:2px;margin:26px 0 30px}
.longread .post-story{margin:26px 0 30px;padding:2px 0 2px 22px;border-left:3px solid var(--amber)}
.longread .post-story p:first-child::first-letter{font:inherit;float:none;margin:0;color:inherit;line-height:inherit}
.longread .post-story p.post-story-by{font-family:var(--mono);font-size:11px;line-height:1.5;letter-spacing:.14em;text-transform:uppercase;color:var(--grey);margin:0}


/* =================================================================
   Fixes and additions — 26 Aug 2026
   ================================================================= */

/* ---- announcement bar: was eating the top of every phone screen ---- */
.ann-link{display:flex;align-items:center;gap:9px;min-width:0;border-bottom:0}
.ann-link b{font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.ann-date{white-space:nowrap;opacity:.85}
.ann-tag{white-space:nowrap;opacity:.7}
.ann-go{opacity:.8}
.ann-link:hover b{text-decoration:underline}
@media(max-width:820px){
  /* No padding on the bar itself: the link carries it, so the whole 34px
     strip is the tap target rather than the one line of text inside it. */
  .ann{padding:0;font-size:11px;letter-spacing:0}
  .ann .wrap{min-height:34px}
  .ann-link{padding-block:9px}
  .ann .dot{width:5px;height:5px}
  .ann-tag{display:none}
}
@media(max-width:520px){
  .ann-date{display:none}
}

/* ---- hero images: portrait crop on phones ---- */
.hero-img picture{display:block;width:100%;height:100%}
@media(max-width:700px){
  .tour-hero{min-height:clamp(500px,72vh,680px)}
  .tour-hero .hero-img img{object-position:center 32%}
}

/* ---- itinerary: collapsible days ---- */
.itin-hint{margin-bottom:6px;display:flex;justify-content:flex-end}
.itin-all{background:none;border:1px solid var(--line);cursor:pointer;color:var(--grey);
  font-family:var(--mono);font-size:11px;letter-spacing:.14em;text-transform:uppercase;
  padding:11px 15px;transition:.2s;border-radius:var(--r)}
.itin-all:hover{border-color:var(--amber);color:var(--ink)}

details.day{border-top:1px solid var(--line)}
details.day:last-of-type{border-bottom:1px solid var(--line)}
/* Bled into the gutter like the tour rows, so the hover highlight has room
   and the chevron on the right cannot sit outside it. */
details.day > summary{
  cursor:pointer;list-style:none;display:grid;align-items:baseline;gap:4px 18px;
  grid-template-columns:auto 1fr auto auto;padding-block:clamp(16px,2.1vw,22px);
  margin-inline:-16px;padding-inline:16px;
  transition:background .25s;
}
details.day > summary::-webkit-details-marker{display:none}
details.day > summary:hover{background:var(--sand)}
.day-n{font-family:var(--mono);font-size:11px;letter-spacing:.16em;text-transform:uppercase;
  color:var(--grey);min-width:52px}
.day-t{font-family:var(--disp);font-weight:700;font-stretch:84%;text-transform:uppercase;
  font-size:clamp(16px,1.9vw,23px);line-height:1.05}
.day-quick{display:flex;gap:14px;font-family:var(--mono);font-size:11.5px;color:var(--grey);white-space:nowrap}
.day-quick em{font-style:normal}
/* No dimming of the figures once a day is open: it was opacity .55, which
   took "18 km" to 2.1:1 on white, and the turned chevron already says the
   day is open. */
.day-chev{width:11px;height:11px;border-right:1.5px solid var(--amber);border-bottom:1.5px solid var(--amber);
  transform:rotate(45deg);transition:transform .3s cubic-bezier(.22,1,.36,1);margin-left:8px;align-self:center}
details.day[open] .day-chev{transform:rotate(-135deg)}
.day-rest .day-t{color:var(--grey)}
.day-body{padding-bottom:clamp(22px,3vw,34px);padding-left:70px}
@media(max-width:760px){
  details.day > summary{grid-template-columns:1fr auto;gap:2px 12px}
  .day-n{grid-column:1;min-width:0}
  .day-chev{grid-column:2;grid-row:1/span 3}
  .day-t{grid-column:1}
  .day-quick{grid-column:1;margin-top:6px}
  .day-body{padding-left:0}
}

/* day detail tabs */
.dtabs{margin-top:20px}

/* The selected tab is a solid ink chip, the same idiom as the gallery
   filters (.gf.on). It had been a 2px underline, which at 11px mono was
   too quiet to read as "selected", and the pane below it had no
   container at all -- so switching tabs changed the words and nothing
   else. The amber rule down the pane is what ties the two together.

   Chips rather than a joined-up tab strip on purpose: the three labels
   wrap onto two rows on a narrow phone, and a tab styled to merge with
   the pane directly beneath it comes apart when a second row lands in
   between. A chip does not care where it sits. */
.dtab-bar{display:none;gap:4px;margin-bottom:14px}
.dtabs.js .dtab-bar{display:flex;flex-wrap:wrap}
/* Same chip again. It had no border-radius at all, which was already out of
   step with .gf and .paytab and shows up now that the shape is a fill. */
.dtab{background:var(--sand-2);border:0;cursor:pointer;border-radius:var(--r);
  font-family:var(--mono);font-size:13px;letter-spacing:.01em;
  color:var(--ink-2);padding:8px 13px;transition:background .18s,color .18s}
.dtab:hover{background:var(--line);color:var(--ink)}
.dtab[aria-selected="true"]{background:var(--ink-surface);color:var(--on-ink)}
.dtabs.js .dpane{border-left:2px solid var(--amber);padding-left:18px}

/* Tighten the chips so all three sit on one line on a phone. Only the
   horizontal padding and the tracking give way -- the vertical padding
   stays, because these are touch targets. */
@media(max-width:560px){
  .dtab{padding:8px 10px}
  .dtab-bar{gap:4px}
  .dtabs.js .dpane{padding-left:14px}
}
.dpane p{margin-bottom:14px;color:var(--prose);max-width:70ch;font-size:16.5px}
.dpane p:last-child{margin-bottom:0}
.dpane-h{font-family:var(--mono);font-size:10.5px;letter-spacing:.16em;text-transform:uppercase;
  color:var(--grey);margin-bottom:12px}
.dtabs.js .dpane-h{display:none}          /* the tab already names it */
.dtabs.js .dpane + .dpane{margin-top:0}
.dpane + .dpane{margin-top:24px}

/* ---- photograph grids become clickable ---- */
.gopen{position:absolute;inset:0;z-index:2;width:100%;height:100%;
  background:none;border:0;padding:0;cursor:zoom-in}
.gopen:focus-visible{outline:2px solid var(--amber);outline-offset:-3px}

/* ---- lightbox ---- */
html.lb-on{overflow:hidden}
/* The phone menu scrolls inside its own 70vh; the page behind it should not
   move at all. Its own class rather than reusing .lb-on, so closing a
   lightbox can never unlock the page while the menu is still open. */
html.nav-on{overflow:hidden}

/* Back to top. Sits below the nav in the stack (50) because it never needs to
   cover it -- one is pinned to the bottom of the screen and the other to the
   top. The arrow is drawn from a rotated border rather than a glyph, so it
   does not depend on a font and cannot come out as a box.

   No shadow. A drop shadow read as a smudge around it on the light sections,
   and this design does not use them at rest anywhere else -- the only shadows
   in the stylesheet are on card hover, at 9%. The faint border stays because
   the footer is also --ink: without it the button would vanish into the one
   place it is most likely to be sitting. */
.totop{position:fixed;right:clamp(14px,2.4vw,28px);bottom:clamp(14px,2.4vw,28px);
  z-index:40;width:46px;height:46px;padding:0;cursor:pointer;
  display:flex;align-items:center;justify-content:center;
  background:var(--ink-surface);color:var(--on-ink);border:1px solid var(--line-d);
  border-radius:var(--r);
  opacity:0;transform:translateY(10px);pointer-events:none;
  transition:opacity .22s,transform .22s,background .18s,border-color .18s}
.totop.on{opacity:1;transform:none;pointer-events:auto}
.totop span{display:block;width:9px;height:9px;margin-top:3px;
  border-left:1.5px solid currentColor;border-top:1.5px solid currentColor;
  transform:rotate(45deg)}
.totop:hover{background:var(--amber);border-color:var(--amber);color:var(--on-accent)}
.totop:focus-visible{outline:2px solid var(--amber);outline-offset:3px}
/* Out of the way of the phone menu, which owns the screen while it is open. */
html.nav-on .totop{opacity:0;pointer-events:none}
@media(prefers-reduced-motion:reduce){.totop{transition:opacity .01s}}
.lb{position:fixed;inset:0;z-index:200;background:rgba(15,11,9,.94);
  display:flex;align-items:center;justify-content:center;padding:clamp(16px,4vw,56px)}
.lb[hidden]{display:none}
.lb-fig{max-width:min(1200px,92vw);max-height:86vh;display:flex;flex-direction:column;gap:14px;margin:0}
.lb-fig img{max-width:100%;max-height:78vh;width:auto;height:auto;object-fit:contain;
  display:block;margin:0 auto;background:var(--ink-surface-2)}
.lb-fig figcaption{color:var(--on-ink-prose);font-size:14.5px;line-height:1.5;text-align:center;max-width:70ch;margin:0 auto}
.lb-x,.lb-nav{position:absolute;background:rgba(246,241,232,.1);border:1px solid rgba(246,241,232,.24);
  color:var(--on-ink);cursor:pointer;transition:.2s;display:flex;align-items:center;justify-content:center;border-radius:var(--r)}
.lb-x{top:clamp(12px,2.4vw,26px);right:clamp(12px,2.4vw,26px);width:46px;height:46px;font-size:26px;line-height:1}
.lb-nav{top:50%;transform:translateY(-50%);width:52px;height:64px;font-size:32px;line-height:1}
.lb-prev{left:clamp(6px,1.6vw,22px)}
.lb-next{right:clamp(6px,1.6vw,22px)}
.lb-x:hover,.lb-nav:hover{background:var(--amber);border-color:var(--amber);color:var(--on-accent)}
.lb-count{position:absolute;bottom:clamp(12px,2.4vw,24px);left:0;right:0;text-align:center;
  font-family:var(--mono);font-size:11px;letter-spacing:.14em;color:var(--on-ink-mute)}
@media(max-width:620px){
  .lb-nav{width:42px;height:52px;font-size:26px}
  .lb-fig img{max-height:70vh}
}

/* ---- /cycling-tours-from-india/: the India hub ----

   Three small additions and one grid. Everything else on that page reuses
   .dtable, .cellx, .grid3, .faq and .prose, which is deliberate: it is a long
   page and a new visual language on it would read as a different site.

   The tables carry .dtable-stack, so below 620px they become cards and every
   cell shows its own heading from data-label. That matters more here than
   anywhere: this table is eight columns wide and a phone would otherwise hide
   the price and the season behind a sideways scroll. */

/* The country under a destination name, and the dates under a price. Both are
   secondary to the cell's own value, so they sit on their own line in the
   mono face at the size the rest of the site uses for a label. */
.ih-country,.ih-dates{display:block;font-family:var(--mono);font-size:11px;
  letter-spacing:.1em;text-transform:uppercase;color:var(--grey);margin-top:5px}
/* The dates cell becomes a link on a row with no dates. Amber rather than
   the grey beside it, because it is the one thing in that cell a reader can
   act on and it would otherwise read as more small print. */
.ih-wait{color:var(--clay);text-decoration:none;border-bottom:1px solid var(--line)}
.ih-wait:hover{border-color:var(--amber);color:var(--ink)}

/* The waitlist form's submit, on touch only. Measured at 41px on an iPhone
   against Apple's 44px minimum, which is the same shortfall the admin
   screens had. SCOPED TO THIS BUTTON, not to .btn: that height is the
   approved design and it carries the Reserve button on every public page,
   so raising it globally would change the thing the design was signed off
   on to fix a form. min-height rather than height, so the label is still
   free to wrap on a narrow screen. */
@media(hover:none),(max-width:760px){
  .wl-form .btn{min-height:44px}
}

/* The waitlist band. Olive, because it is the booking band for a tour that
   cannot take a booking yet, and because the sections around it are
   conditional so it cannot be tuned against its neighbour.

   THE TEXT COLOURS ARE STATED, NOT INHERITED, and that is the whole care
   needed here. .field label is var(--grey) and the "required" marker is
   var(--clay); both are chosen for a light ground and neither is readable
   on olive. This is the same fault .cellx had when it first appeared on a
   light band, so the rule is the same: a block that changes its ground
   states the colours that sit on it.

   The inputs themselves are left alone. .field input is already ink on
   white with a hairline border, which is exactly right on olive and needs
   nothing. */
.sec.wl-band{background:var(--olive);color:var(--on-ink)}
.sec.wl-band .kicker{color:var(--on-olive)}
.sec.wl-band .lede{color:var(--on-olive-prose)}
.sec.wl-band .fine{color:var(--on-olive)}
.sec.wl-band .field label{color:var(--on-olive-prose)}
.sec.wl-band .field label span{color:var(--honey)}
/* .notice keeps its sand panel and its amber rule, which reads correctly on
   olive without help; only the text inside it needs its own colour back,
   because the band above set #fff on everything. */
.sec.wl-band .notice{color:var(--ink)}
.sec.wl-band .notice .fine{color:var(--prose-soft)}
/* The riding season, stated on its own line rather than buried in the lede.
   The label is the mono/tracked treatment every other spec value on the site
   uses; the month is the condensed display face, because it is the one thing
   in this block somebody scans for. */
.wl-season{display:flex;flex-wrap:wrap;align-items:baseline;gap:6px 12px;margin-top:18px}
.wl-season span{font-family:var(--mono);font-size:11px;letter-spacing:.16em;
  text-transform:uppercase;color:var(--on-olive)}
.wl-season b{font-family:var(--disp);font-weight:700;font-stretch:84%;
  text-transform:uppercase;font-size:clamp(20px,2.4vw,27px);line-height:1;color:var(--honey)}
/* The fine print under it explains the distinction and should sit close. */
.wl-season + .fine{margin-top:8px}
/* The button needs air between it and the season line above it. The caveat
   sits tight under the months on purpose, because the two are one thought;
   the button is a different one and was reading as part of the same block. */
.wl-band .acts{margin-top:clamp(26px,3vw,36px)}
/* The same season line inside the popup, where the ground is light and the
   block has less room than the olive band. */
.wl-season-sm{margin-top:14px}
.wl-season-sm span{color:var(--grey)}
.wl-season-sm b{color:var(--clay);font-size:clamp(17px,1.9vw,21px)}
.wl-season-sm[hidden]{display:none}
/* The dialog is a form rather than prose, so it wants the reading width of
   one, and it has to scroll on a short screen with the keyboard up. */
.wl-box{max-width:560px;width:100%}
.wl-box .eform{margin-top:20px;max-width:none}
.wl-box .frow{display:grid;gap:0 18px;grid-template-columns:1fr 1fr}
.wl-box .frow .field:last-child{grid-column:1 / -1}
/* [hidden] on each of these, not the bare class. The rule used to read
   `.wl-sending,.wl-failed,...` which set display:none unconditionally, so
   the script could unhide the sending line all it liked and nothing ever
   appeared: the submit simply went blank until the answer came back. That is
   why an indicator that existed was never seen. */
.wl-sending[hidden],.wl-failed[hidden],.wl-done[hidden],
.wl-box [data-wl-ask][hidden]{display:none}
.wl-failed{margin-top:14px}
.wl-done:focus{outline:none}

/* WHILE THE POST IS IN FLIGHT. A form that goes quiet reads as broken, and
   this one is talking to Brevo and Meta behind the scenes so it is not
   always instant. */
.wl-sending{display:flex;align-items:center;gap:10px;margin-top:16px;color:var(--grey)}
.wl-spin{width:16px;height:16px;flex:none;border-radius:50%;
  border:2px solid var(--line);border-top-color:var(--amber);
  animation:wl-turn .7s linear infinite}
@keyframes wl-turn{to{transform:rotate(360deg)}}
/* The one motion rule here, and it stops for anyone who has asked for less.
   The dot still changes colour so the state is not carried by movement
   alone. */
@media(prefers-reduced-motion:reduce){
  .wl-spin{animation:none;border-top-color:var(--amber);border-right-color:var(--amber)}
}
/* The form dims rather than disappearing, so the fields somebody just filled
   are still there if it fails. */
.wl-box form.is-sending .frow{opacity:.55;transition:opacity .2s}
@media(max-width:560px){
  .wl-box .frow{grid-template-columns:1fr}
  .wl-box .btn{min-height:44px}
}

/* The Indian tours, set apart from the table above rather than appended to
   it, because the section heading says "abroad" and these are not. */
.ih-home{margin-top:clamp(34px,4vw,54px);padding-top:clamp(26px,3vw,38px);
  border-top:1px solid var(--line)}
.ih-home .lede{margin-bottom:22px}

/* Twelve month cards. Month first, not destination first: the question this
   answers is "I am free in February, where can I go", and a twelve-column
   destination matrix answers the other one and cannot be read on a phone.
   auto-fit rather than a fixed count, so it runs 4 / 3 / 2 / 1 across the
   range without a breakpoint per step. */
.months{display:grid;gap:2px;margin-top:26px;
  grid-template-columns:repeat(auto-fit,minmax(190px,1fr))}
.month{background:var(--sand-2);padding:20px 18px}
.month h3{font-family:var(--mono);font-size:11px;letter-spacing:.16em;
  text-transform:uppercase;color:var(--grey);margin-bottom:12px}
.month ul{list-style:none;margin:0;padding:0}
.month li+li{margin-top:7px}
.month a{font-family:var(--disp);font-weight:700;font-stretch:84%;
  text-transform:uppercase;font-size:16px;line-height:1.1;color:var(--ink);
  text-decoration:none;border-bottom:1px solid transparent;transition:border-color .18s}
.month a:hover{border-color:var(--amber)}
/* A month with nothing against it stays on the grid rather than being
   dropped. An empty May is a real answer, and a missing card reads as an
   oversight. Held back visually so the full months carry the eye. */
.month-none{background:var(--sand)}
.month-none .fine{margin:0;color:var(--grey)}

/* ---- the tour page's photograph strip ----

   A tour carries up to forty photographs and the shared .gg grid stacks them
   three columns deep, which on a tour page ran to several screens of height
   between the itinerary and the private-groups section. Sampath asked for a
   horizontal strip instead, 31 Aug 2026.

   IT IS A SEPARATE CLASS, NOT A MODIFIER ON .gg, and that is deliberate.
   /gallery/ and the blog posts share .gg and neither was asked to change;
   .gg keeps columns:3 untouched and only tour.php uses this. .gcell is
   still shared, so the warm wash, the clipping and the lightbox trigger are
   the same objects here as everywhere else rather than a second copy.

   FIXED HEIGHT, VARIABLE WIDTH. The rule on this site is that a photograph
   is shown whole or not at all, so the strip pins the one dimension a row
   needs to share and lets each photograph keep its own aspect ratio. A
   landscape shot is simply wider than a portrait one.

   Built on the .quotes idiom already here: a scroll-snapping row rather
   than a carousel, no visible scrollbar, the part-shown photograph at the
   edge doing the work of telling you there is more. It scrolls by wheel,
   trackpad, swipe and keyboard whether or not the drift below is running. */
.ggs{
  display:flex;gap:2px;
  overflow-x:auto;overscroll-behavior-x:contain;
  /* Proximity rather than mandatory: a swipe lands on a photograph's edge
     when it comes to rest near one, and is left alone when the reader
     clearly meant to stop between two. Mandatory would take that choice
     away on a row whose cells are all different widths. */
  scroll-snap-type:x proximity;
  /* No visible scrollbar. The part-shown photograph at the right edge is
     the affordance, which is the bargain .quotes already makes. */
  scrollbar-width:none;
  /* The row is the scroll container, so it takes the focus ring rather than
     a child, and it is focusable so a keyboard can drive it. */
  outline-offset:3px;
}
.ggs::-webkit-scrollbar{display:none}
.ggs .gcell{
  flex:0 0 auto;margin:0;
  height:clamp(210px,26vw,340px);
  scroll-snap-align:start;
  /* THE PEEK IS GUARANTEED BY THIS LINE. Sampath asked for part of the next
     photograph to show, so it is clear the strip scrolls, and with cells
     sized from their own aspect ratios that was luck rather than design: a
     wide enough photograph filled the container and the strip looked like a
     single picture with nothing after it. Capping a cell at 82% of the row
     leaves a fifth of the next one showing whatever shape the current one
     is.

     It only ever binds on a genuinely wide photograph. A 3:2 landscape at
     this height is well inside the cap and is untouched. */
  max-width:82%;
}
/* width:auto is what lets the aspect ratio decide how wide each cell is.
   max-width:none overrides the shared rule, which is written for a column
   grid where the photograph fills the column.

   aspect-ratio:auto 3/2 IS LOad-ORDER PLUMBING, not a crop. width:auto on an
   image that has not loaded resolves to zero, so every cell was zero wide,
   so the whole strip was zero wide, so none of the lazy images ever came
   into view to load: a standstill that measured as an empty strip. The
   `auto` keyword means "use the real ratio once you have it, and 3:2 until
   then", which gives the browser a width to lay out from on the first pass
   and lets each photograph settle to its own shape as it arrives.

   object-fit:contain rather than cover, so the rule that a photograph is
   shown whole or not at all still holds if a cell is ever wider than its
   picture. Nothing here is cropped. */
.ggs .gcell img{height:100%;width:auto;max-width:100%;object-fit:contain;
  aspect-ratio:auto 3/2}

/* The drift stops for anyone who has asked for less movement. The strip
   still scrolls by hand; it simply does not move on its own. */
@media(prefers-reduced-motion:reduce){
  .ggs{scroll-behavior:auto}
}


/* =================================================================
   Grade help — the "?" beside Grade in the spec strip
   ================================================================= */

/* THE AVAILABILITY DOT, beside a departure's dates.

   The same pulse the announcement bar uses, so "something is live here"
   reads the same way twice on the site rather than as a new idiom.

   The colour is never the only signal: the words are printed right beside
   it on a tour page and sit in a title on the index, because roughly one
   man in twelve cannot separate the red from the green. The dot is
   aria-hidden where the label is already in the markup -- a screen reader
   saying "green dot, booking open" is the same thing twice.

   Green and red are the two the palette does not contain -- CLAUDE.md is
   explicit that there is no red on this site. These are the smallest
   exception that can work: 7px, and only ever as a status light. They are
   NOT tokens and must not be used for anything else. Amber is the palette's
   own honey for "limited", which is what the announcement bar already
   pulses in, and closed is a grey that recedes rather than alarms. */
.avdot{width:7px;height:7px;border-radius:50%;display:inline-block;flex:none;
  margin-right:7px;vertical-align:middle;background:var(--grey);
  animation:pulse 2.4s ease-in-out infinite}
.av-open{background:#3F8F4F}
.av-limited{background:var(--honey)}
.av-full{background:#B23A2E}
.av-closed{background:var(--grey);animation:none}

/* A tour page prints the words beside the dot, so the em wraps as a unit. */
.depstatus .avdot{margin-right:6px}
/* On the index the dot sits in front of the dates. */
.tour .price .avdot{margin-right:8px}
/* Two dates on one card stack, each answering for itself, rather than
   collapsing into "Dec 2026 & Jan 2027" under a single dot that cannot say
   one is full and the other open. Aligned to the top of the row so the
   price beside them does not drift down with the second line. */
.price.dates{display:flex;flex-direction:column;gap:5px;align-self:flex-start}
.price .dateline{display:flex;align-items:center;white-space:nowrap}

/* Somebody who has asked for less movement gets a dot that still says
   which colour it is, and stops moving. Same guard the rest of the motion
   on this site sits behind. */
@media(prefers-reduced-motion:reduce){.avdot{animation:none}}

.qmark{
  display:inline-flex;align-items:center;justify-content:center;
  width:15px;height:15px;margin-left:5px;padding:0;flex:none;vertical-align:middle;
  border:1px solid currentColor;border-radius:50%;background:none;color:inherit;cursor:pointer;
  font-family:var(--mono);font-size:9px;line-height:1;letter-spacing:0;
  opacity:.78;transition:.18s;position:relative;
}
.qmark:hover{opacity:1;background:var(--amber);border-color:var(--amber);color:var(--on-accent)}
.spec dt{display:flex;align-items:center}

/* the listing-page equivalent, which cannot sit inside the card link */
.gradelink{
  display:inline-flex;align-items:center;gap:7px;margin-top:12px;
  background:none;border:0;padding:0;cursor:pointer;
  font-family:var(--mono);font-size:11px;letter-spacing:.13em;text-transform:uppercase;
  color:var(--clay);transition:color .18s;
}
.gradelink:hover{color:var(--ink)}
.gradelink .qmark{opacity:1;width:16px;height:16px;margin:0}
.gradelink:hover .qmark{background:var(--amber);border-color:var(--amber);color:var(--on-accent)}

/* "Payment schedule ?" under the prices on a tour page, opening the same
   kind of dialog. Clay and hovering to ink, exactly as .gradelink does: the
   tour page's booking band is .reserve-light, so this sits on white, and an
   inherited near-black read as body copy rather than as something to press.
   The dark olive .reserve band keeps currentColor below, where clay would
   barely show. */
.payplan-open{
  display:inline-flex;align-items:center;gap:7px;margin-top:16px;
  background:none;border:0;padding:0;cursor:pointer;text-align:left;
  font-family:var(--mono);font-size:11px;letter-spacing:.13em;text-transform:uppercase;
  color:var(--clay);transition:color .18s;
}
.payplan-open:hover{color:var(--ink)}
.payplan-open .qmark{opacity:1;width:16px;height:16px;margin:0}
.payplan-open:hover .qmark{background:var(--amber);border-color:var(--amber);color:var(--on-accent)}
.reserve:not(.reserve-light) .payplan-open{color:inherit;opacity:.82}
.reserve:not(.reserve-light) .payplan-open:hover{color:inherit;opacity:1}
/* Inside the popup the heading already spaces the rows; the 26px it carries
   on the booking band leaves a hole under the lede. */
.gh-box .payplan{margin-top:18px}

/* the popup itself */
.gh{position:fixed;inset:0;z-index:210;background:rgba(15,11,9,.72);
  display:flex;align-items:center;justify-content:center;padding:clamp(14px,4vw,44px)}
.gh[hidden]{display:none}
.gh-box{position:relative;background:var(--white);color:var(--ink);
  max-width:640px;width:100%;max-height:88vh;overflow-y:auto;
  padding:clamp(24px,3.4vw,40px);border-top:3px solid var(--amber);
  border-radius:0 0 var(--r-card) var(--r-card)}
.gh-x{position:absolute;top:10px;right:10px;width:38px;height:38px;font-size:24px;line-height:1;
  background:none;border:0;color:var(--grey);cursor:pointer;transition:color .18s}
.gh-x:hover{color:var(--ink)}
.gh-lede{color:var(--prose);font-size:15.5px;margin-top:10px}
.gh-levels{margin-top:22px;border-top:1px solid var(--line)}
.gh-level{padding-block:16px;border-bottom:1px solid var(--line)}
.gh-level.on{background:var(--sand);margin-inline:calc(-1 * clamp(24px,3.4vw,40px));
  padding-inline:clamp(24px,3.4vw,40px);border-left:3px solid var(--amber)}
.gh-head{display:flex;align-items:center;gap:12px}
.gh-head h3{font-family:var(--disp);font-weight:700;font-stretch:84%;text-transform:uppercase;font-size:19px;line-height:1.05}
.gh-tag{font-family:var(--mono);font-size:10px;letter-spacing:.14em;text-transform:uppercase;
  background:var(--amber);color:var(--on-accent);padding:4px 8px}
.gh-nums{display:flex;gap:26px;margin:10px 0 8px}
.gh-nums dt{font-family:var(--mono);font-size:10px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--grey);margin-bottom:3px}
.gh-nums dd{font-family:var(--disp);font-weight:700;font-stretch:84%;font-size:17px}
.gh-level p{font-size:15px;color:var(--prose);line-height:1.55}
.gh-you{margin-top:20px;padding:14px 16px;background:var(--ink-surface);color:var(--on-ink-prose);font-size:15px;line-height:1.55}
.gh-you b{color:var(--honey);font-weight:500}
.gh-more{margin-top:16px;font-size:14.5px;color:var(--prose)}
/* The per-tour grading note, marked like the refund deadline because it
   is the same kind of thing: the one line that qualifies what is above. */
.gh-note{margin-top:14px;border-left:3px solid var(--amber);padding:2px 0 2px 13px;
  font-size:14.5px;line-height:1.55;color:var(--prose)}
.gh-more a{border-bottom:1px solid var(--amber)}
@media(max-width:520px){
  .gh{padding:0;align-items:flex-end}
  /* A bottom sheet on a phone: its lower corners are the screen's edge. */
  .gh-box{max-height:92vh;border-top-width:4px;border-radius:0}
  .gh-nums{gap:18px}
}

.glevel-copy{margin-top:12px;color:var(--prose-strong)}

/* The "?" is deliberately small, but a 15px tap target is not enough on a
   phone. Extend the hit area with a pseudo-element instead of growing it. */
.qmark::after{content:"";position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);
  width:44px;height:44px}
@media(hover:hover){.qmark::after{width:26px;height:26px}}

/* =================================================================
   Tour FAQs
   ================================================================= */

.faqs{margin-top:clamp(26px,3.5vw,44px);border-top:1px solid var(--line-d)}
.faq{border-bottom:1px solid var(--line-d)}
.faq > summary{
  cursor:pointer;list-style:none;display:flex;align-items:flex-start;gap:18px;
  padding-block:clamp(15px,1.9vw,19px);transition:color .2s;
}
.faq > summary::-webkit-details-marker{display:none}
.faq > summary:hover{color:var(--honey)}
.faq-q{font-size:clamp(15.5px,1.5vw,17.5px);line-height:1.45;font-weight:500;flex:1}
.faq-mark{position:relative;flex:none;width:13px;height:13px;margin-top:5px}
.faq-mark::before,.faq-mark::after{content:"";position:absolute;background:var(--amber);
  transition:transform .3s cubic-bezier(.22,1,.36,1)}
.faq-mark::before{top:6px;left:0;width:13px;height:1.5px}
.faq-mark::after{left:6px;top:0;width:1.5px;height:13px}
.faq[open] .faq-mark::after{transform:scaleY(0)}
.faq[open] .faq-q{color:var(--honey)}
.faq-a{padding-bottom:clamp(16px,2.2vw,22px);max-width:74ch}
.faq-a p{color:var(--on-ink-prose);font-size:16px;line-height:1.65;margin-bottom:12px}
.faq-a p:last-child{margin-bottom:0}
.faq-ask{border-bottom:1px solid var(--amber)}

/* =================================================================
   Tour rows and section heads on a phone
   ================================================================= */

@media(max-width:760px){
  /* 3. Section headings and their button stacked with the button pushed to
        the far right, which read as a mistake. Stack them left. */
  .sec-head{display:block}
  .sec-head .right{margin-left:0;margin-top:18px}
  .sec-head .btn.right{display:inline-block}
  .sec-head .lede.right{max-width:none}

  /* 4a. .shotwrap reserves 16px on the left for the amber slide-in block,
         which is a hover effect phones never see — it just made the photo
         narrower than the text and pushed it out of alignment. */
  .shotwrap{padding:0}
  .shotwrap::before{display:none}

  /* 4b. margin-left:auto threw the CTA to the far right, away from the
         price and dates it belongs with. Let the row stack naturally. */
  .row{gap:8px 18px}
  .go{margin-left:0;width:100%;padding-top:4px}
}


/* Gallery captions were pinned open on touch devices, so on phones every
   photograph carried a block of text across it. The caption now belongs to
   the lightbox; on pointer devices it still fades in on hover. */
@media(hover:none),(max-width:760px){
  .gcell figcaption{display:none}
}

/* filter chips were one-per-row on a phone; let them sit two or three up */
@media(max-width:560px){
  .gfilter{gap:6px}
  /* Only the padding gives way now. The old rule also dropped to 10.5px and
     re-tightened the tracking, both of which were compensating for capitals
     that are no longer there. */
  .gf{padding:7px 11px}
}

/* =================================================================
   Rider photographs, and the documentaries
   ================================================================= */

/* the face beside each quote */
.face{width:56px;height:56px;flex:none;margin-top:2px;border-radius:50%;object-fit:cover;
  background:var(--sand-2);filter:saturate(.92)}
.whotext{min-width:0}

/* film grid */
.films{display:grid;grid-template-columns:repeat(2,1fr);gap:clamp(20px,2.6vw,34px);
  margin-top:clamp(26px,3.5vw,44px)}
@media(max-width:820px){.films{grid-template-columns:1fr}}
/* A tour has one film, not four. Left-aligned at half width rather than
   stretched across the section, which at 1280px would put a 1,100px-wide
   16:9 video above a two-column page and dwarf everything under it. */
.films-one{grid-template-columns:minmax(0,1fr);max-width:760px}
/* The same single-item variant for a lone blog card on a tour page.
   .posts is a two-column grid and one card in it stretched to half the
   page with a hole beside it. */
.posts-one{grid-template-columns:minmax(0,1fr);max-width:760px}
/* THE READING SECTION AT THE FOOT OF A TOUR PAGE, three-up. Sampath's
   instruction, 2 Sep 2026: .posts is two columns, and two cards at half the
   content width read as heavy under a long tour page. Three-up puts them at
   the size cards are everywhere else on the site, and two of them then sit
   left in the grid with the third track empty, which is correct rather than a
   gap to fill.

   A tour gets ONE of these classes, never both: they set the same property, so
   which one won would come down to file order, and that is not a thing to
   leave to chance on a live page. tour.php picks. */
.posts-three{grid-template-columns:repeat(3,minmax(0,1fr))}
@media(max-width:980px){.posts-three{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media(max-width:820px){.posts-three{grid-template-columns:minmax(0,1fr)}}
/* A SHALLOWER PHOTOGRAPH ON DESKTOP, on Sampath's instruction. 16/9 across
   760px is 428px of picture, and stacked under a section heading at the foot
   of an already long tour page the whole block was taller than what it is
   pointing at. 21/9 takes about a hundred pixels out of it and still reads
   as a photograph rather than a strip.

   Desktop only, at the same 760px the rest of this file splits on: on a
   phone the card is the width of the screen, 16/9 is already shallow in
   absolute terms, and going wider would leave a letterbox.

   Scoped to .posts-one, so the cards on /blogs/ keep the ratio they were
   designed at. */
@media(min-width:761px){
  .posts-one .pshot{aspect-ratio:21/9}
}

/* -----------------------------------------------------------------
   THE BLOG, RE-CUT FOR TWENTY-SIX POSTS. 1 Oct 2026.

   THREE-UP CARDS ARE SIZED TO THE CARD. .d3 is a section-scale heading, up
   to 31px, and a title like "Riding in a Group: Pace Lines and Etiquette for
   Your First Cycling Tour" took five lines of it in a 370px card. 20px is
   what the archive cards on /tours/ already use at this width. Scoped to
   the blog's own two grids: the two-post row at the foot of a tour page is
   the same card at the same width and keeps the size Sampath approved for
   it on 2 Sep 2026 until he says otherwise.
   ----------------------------------------------------------------- */
:is(.posts-index,.posts-next) .post .pbody{padding:18px 20px 22px}
:is(.posts-index,.posts-next) .post .d3{font-size:clamp(18px,1.55vw,21px);line-height:1.12;margin:9px 0 9px}
:is(.posts-index,.posts-next) .post .pex{font-size:15px;line-height:1.55}
.post .where{letter-spacing:.12em}

/* THE NEWEST POST, DRAWN LARGE. "The first card that is not hidden", so it
   is the newest post in whatever category the filter is showing and nothing
   has to tell it when the filter changes. A browser too old for
   :nth-child(of) drops these rules and shows an ordinary first card. */
@media(min-width:821px){
  .posts-index > .post:nth-child(1 of :not([hidden])){
    grid-column:1 / -1;display:grid;grid-template-columns:1.3fr 1fr}
  .posts-index > .post:nth-child(1 of :not([hidden])) .pshot{aspect-ratio:16/9;height:100%}
  .posts-index > .post:nth-child(1 of :not([hidden])) .pbody{
    justify-content:center;padding:clamp(24px,3vw,44px)}
  .posts-index > .post:nth-child(1 of :not([hidden])) .d3{
    font-size:clamp(24px,2.5vw,34px);line-height:1.08;margin:12px 0 12px}
  .posts-index > .post:nth-child(1 of :not([hidden])) .pex{font-size:16.5px;line-height:1.6;-webkit-line-clamp:4;line-clamp:4}
  .posts-index > .post:nth-child(1 of :not([hidden])) .go{margin-top:0;padding-top:20px}
}

/* ON A PHONE, EVERY CARD AFTER THE FIRST IS A ROW: a small photograph, the
   category and date, and the title. Twenty-six full cards measured 17,544px
   of scrolling on an iPhone; a reader looking for one post was past the
   point of finding it. The newest keeps its full card, photograph and
   excerpt and all. The excerpt and "Read it" go from the rows, since the
   titles say what each post is; the whole row is still the link. The three
   "keep reading" cards at the foot of a post are rows on a phone too. */
@media(max-width:560px){
  .posts-index,.posts-next{gap:0}
  .posts-index > .post:nth-child(1 of :not([hidden])){margin-bottom:10px}
  .posts-index > .post:not(:nth-child(1 of :not([hidden]))),
  .posts-next > .post{
    display:grid;grid-template-columns:104px 1fr;gap:0 14px;align-items:start;
    background:none;border-top:1px solid var(--line);border-radius:0;padding-block:16px;
    transform:none;box-shadow:none}
  .posts-index > .post:not(:nth-child(1 of :not([hidden]))) .pshot,
  .posts-next > .post .pshot{aspect-ratio:1;border-radius:var(--r)}
  .posts-index > .post:not(:nth-child(1 of :not([hidden]))) .pbody,
  .posts-next > .post .pbody{padding:0}
  .posts-index > .post:not(:nth-child(1 of :not([hidden]))) .where,
  .posts-next > .post .where{font-size:10px;letter-spacing:.1em}
  .posts-index > .post:not(:nth-child(1 of :not([hidden]))) .d3,
  .posts-next > .post .d3{font-size:17px;line-height:1.14;margin:6px 0 0}
  .posts-index > .post:not(:nth-child(1 of :not([hidden]))) .pex,
  .posts-index > .post:not(:nth-child(1 of :not([hidden]))) .go,
  .posts-index > .post:not(:nth-child(1 of :not([hidden]))) .pmin,
  .posts-next > .post .pex,
  .posts-next > .post .go,
  .posts-next > .post .pmin{display:none}
  .posts-next > .post:last-child{border-bottom:1px solid var(--line)}
}

/* ---- a post ---- */
/* The category above the title is a link back to its list. Inherits the
   kicker's colour; the underline is the signal, as on every text link. */
.phero .kicker a{border-bottom:1px solid color-mix(in srgb, var(--amber) 60%, transparent);transition:border-color .18s,color .18s}
.phero .kicker a:hover,.phero .kicker a:focus-visible{color:var(--on-ink);border-bottom-color:currentColor}
/* The photograph under the title is a <picture> now, so a phone can be sent
   the smaller file. Same sizing rule .hero-img picture has. */
.break picture{display:block;width:100%;height:100%}

/* IN THIS POST, in the sidebar. A hairline down the left with the section
   on screen marked in amber: the mark is set by the script that lights the
   tour page's jump links, and without it the list is simply a list. */
.pside-post ul + h3,.pside-post nav + h3{margin-top:26px}
.ptoc ul{gap:0;border-left:1px solid var(--line)}
.ptoc a{display:block;padding:6px 0 6px 14px;margin-left:-1px;border-left:2px solid transparent;
  font-size:14.5px;line-height:1.4;transition:color .18s,border-color .18s}
.ptoc a.is-on{color:var(--ink);border-left-color:var(--amber)}
/* The post's sidebar holds a contents list of up to thirteen lines plus the
   tour, and it sticks; on a short laptop screen that is taller than the
   space under the nav, so it scrolls inside itself rather than running off
   the bottom where its last lines could never be reached. */
.pside-post{max-height:calc(100vh - var(--stickytop) - 20px);overflow-y:auto}
/* THE READING COLUMN IS CENTRED in the space left of the sidebar. It is
   held to 600px for its line length, and sat at the left of a 1fr track
   with a wide empty gap between it and the sidebar. Sampath, 6 Oct 2026:
   centre the column; the sidebar stays where it is. Posts only (.pcols-post):
   the policy, contact and tour pages use .pcols at full width. */
.pcols-post .longread{margin-inline:auto}
/* The tour a post is about: its name, then dates and price underneath. */
.pside-tours b{display:block;font-weight:600;color:var(--ink);font-size:15.5px;line-height:1.3}
.pside-tours span{display:block;font-family:var(--mono);font-size:11px;letter-spacing:.04em;
  color:var(--prose-soft);margin-top:4px;line-height:1.5}
.pside-tours a{display:block}
.pside-tours a:hover b{color:var(--clay)}

/* The same list on a phone, folded shut above the article; see post.php.
   Only one of the two lists is ever drawn. */
.ptoc-m{display:none}
@media(max-width:900px){
  .pside-post{max-height:none;overflow:visible}
  .pside-post .ptoc{display:none}
  .pside-post .ptoc + h3{margin-top:0}
  .ptoc-m{display:block;margin-bottom:26px;border:1px solid var(--line);border-radius:var(--r-card);background:var(--sand)}
  .ptoc-m > summary{list-style:none;cursor:pointer;display:flex;align-items:center;gap:10px;
    min-height:48px;padding:0 16px;font-family:var(--mono);font-size:11.5px;letter-spacing:.14em;
    text-transform:uppercase;color:var(--ink)}
  .ptoc-m > summary::-webkit-details-marker{display:none}
  .ptoc-m > summary span{color:var(--prose-soft);letter-spacing:.06em}
  .ptoc-m > summary::after{content:"";margin-left:auto;width:8px;height:8px;margin-top:-4px;
    border-right:1.5px solid var(--amber);border-bottom:1.5px solid var(--amber);transform:rotate(45deg)}
  .ptoc-m[open] > summary::after{transform:rotate(-135deg);margin-top:4px}
  .ptoc-m ul{list-style:none;padding:2px 16px 10px;border-top:1px solid var(--line)}
  .ptoc-m li a{display:block;padding:11px 0;font-size:15.5px;line-height:1.35;color:var(--prose-strong);
    border-bottom:1px solid var(--line)}
  .ptoc-m li:last-child a{border-bottom:0}
}

/* A WIDE TABLE IN A POST SAYS THAT IT SCROLLS. The gearing post's tables are
   eight columns; on a phone the last three were past the edge with nothing
   to show they existed, and they are the low gears the post goes on to
   recommend. Two things. The cells tighten on a phone, which is enough for
   most tables to fit outright. And where one still does not, a soft edge on
   the side with more to see: drawn with background-attachment, so it is
   there only while there is something past that edge, and needs no script.
   Scoped to a post, where the ground behind the table is always the page. */
.longread .tablewrap{
  background:
    linear-gradient(to right, var(--page) 40%, transparent) left center / 28px 100% no-repeat local,
    linear-gradient(to left, var(--page) 40%, transparent) right center / 28px 100% no-repeat local,
    linear-gradient(to right, color-mix(in srgb, var(--ink) 18%, transparent), transparent) left center / 14px 100% no-repeat scroll,
    linear-gradient(to left, color-mix(in srgb, var(--ink) 18%, transparent), transparent) right center / 14px 100% no-repeat scroll}
@media(max-width:560px){
  .longread .dtable{font-size:13.5px}
  .longread .dtable th,.longread .dtable td{padding:9px 4px 9px 5px}
  .longread .dtable th{letter-spacing:.02em}
  .longread .dtable td:first-child{font-size:12px}
}
.film{display:flex;flex-direction:column}
.film-play{position:relative;display:block;width:100%;padding:0;border:0;cursor:pointer;
  background:var(--ink-surface-2);aspect-ratio:16/9;overflow:hidden;border-radius:var(--r-card)}
.film-play img{width:100%;height:100%;object-fit:cover;transition:transform .8s cubic-bezier(.22,1,.36,1),opacity .3s}
.film-play:hover img{transform:scale(1.04);opacity:.82}
.film-icon{position:absolute;inset:0;margin:auto;width:64px;height:64px;
  background:rgba(25,19,16,.62);border:1px solid rgba(246,241,232,.4);border-radius:50%;
  transition:.25s cubic-bezier(.22,1,.36,1)}
.film-icon::after{content:"";position:absolute;top:50%;left:54%;transform:translate(-50%,-50%);
  border-style:solid;border-width:11px 0 11px 18px;border-color:transparent transparent transparent var(--on-ink)}
.film-play:hover .film-icon{background:var(--amber);border-color:var(--amber);transform:scale(1.06)}
.film-play:hover .film-icon::after{border-left-color:var(--on-accent)}
.film-play:focus-visible{outline:2px solid var(--amber);outline-offset:3px}
.film-body{padding-top:16px}
/* These were #fff and a warm grey outright, which was safe while films
   only ever appeared on the dark homepage band. A tour page shows one on
   white, where a white heading is invisible. Colour is scoped to the
   ground now; the homepage is unchanged. */
.film-body .d3{font-size:clamp(17px,1.8vw,21px)}
.film-body p{font-size:15.5px;line-height:1.55;margin-top:11px;max-width:52ch;color:var(--prose-soft)}
.dark .film-body .d3{color:var(--on-ink)}
.dark .film-body p{color:var(--on-ink-prose)}
/* once playing, the iframe takes the thumbnail's place */
.film-play iframe{position:absolute;inset:0;width:100%;height:100%;border:0}

/* =================================================================
   About: the archive strip
   ================================================================= */

.archive-strip{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(14px,1.8vw,22px);
  margin-top:clamp(26px,3.5vw,44px)}
@media(max-width:820px){.archive-strip{grid-template-columns:repeat(2,1fr)}}
@media(max-width:520px){.archive-strip{grid-template-columns:1fr}}
.arch{position:relative;margin:0;background:var(--white);display:flex;flex-direction:column;border-radius:var(--r-card);overflow:hidden}
.arch img{aspect-ratio:4/3;object-fit:cover;width:100%;height:auto}
.arch figcaption{padding:14px 16px 16px}
.arch figcaption b{display:block;font-family:var(--mono);font-size:11px;letter-spacing:.16em;
  color:var(--clay);margin-bottom:6px}
.arch figcaption span{display:block;font-size:14.5px;line-height:1.5;color:var(--prose)}
.arch .gopen{inset:0 0 auto 0;height:auto;aspect-ratio:4/3}

/* On phones the team photo sat in its own 110px column beside a much taller
   bio, leaving a long empty gap underneath it. Put the portrait alongside
   the name and role instead, and let the bio run the full width below. */
@media(max-width:640px){
  .member{
    grid-template-columns:68px 1fr;
    grid-template-areas:"photo name" "photo role" "bio bio";
    align-items:start;
    gap:0 16px;
  }
  .mphoto{grid-area:photo;align-self:start}
  .mbody{display:contents}
  .mbody > .d3{grid-area:name;align-self:end}
  .mbody > .mrole{grid-area:role;align-self:start;margin:5px 0 0}
  .mbody > p:last-child{grid-area:bio;margin-top:16px}
}

/* -----------------------------------------------------------------
   THE TRAINING PLAN
   -----------------------------------------------------------------
   Two surfaces: the five-question form on the booking page (.tform), and
   the plan itself (.tplan), which has to read on a phone AND come out of a
   printer as a document somebody tapes to a wall.

   Every colour is a token. The print block at the bottom is the only place
   on this site that sets ink on paper, and it deliberately drops the site
   furniture rather than trying to shrink it.
   ----------------------------------------------------------------- */

/* ---- the form on the booking page ---- */
.bk-train{margin-top:14px;border:1px solid var(--line);border-radius:var(--r-card);background:var(--sand)}
.bk-train>summary{cursor:pointer;padding:14px 18px;font-family:var(--mono);font-size:11px;
  letter-spacing:.16em;text-transform:uppercase;color:var(--prose-strong)}
.bk-train>summary:focus-visible{outline:2px solid var(--amber);outline-offset:2px}
.bk-train-body{padding:0 18px 18px}
.bk-train-go{margin-top:12px}
.tform-q{border:0;padding:0;margin:0 0 20px}
.tform-q legend{font-weight:600;font-size:16px;color:var(--prose-strong);margin-bottom:4px}
.tform-q .fine{margin:0 0 10px}
.tform-opts{display:flex;flex-wrap:wrap;gap:8px}
.tform-opt{display:inline-flex;align-items:center;gap:8px;cursor:pointer;
  border:1px solid var(--line);border-radius:var(--r);padding:9px 13px;background:var(--page);
  font-size:15px;line-height:1.3}
.tform-opt:hover{border-color:var(--amber)}
.tform-opt input{accent-color:var(--amber);margin:0}
/* The chosen one reads as chosen without colour alone carrying it: the
   border thickens as well, for anyone who cannot separate the two. */
.tform-opt:has(input:checked){border-color:var(--amber);box-shadow:inset 0 0 0 1px var(--amber)}
.tform-opt:has(input:focus-visible){outline:2px solid var(--amber);outline-offset:2px}

/* ---- the plan ---- */
.tplan .wrap{max-width:820px}
.tp-bar{display:flex;flex-wrap:wrap;gap:10px;margin-bottom:14px}
.tp-head{margin:22px 0 8px}
.tp-meta,.tp-facts,.tp-zones{display:grid;gap:0;margin:18px 0 6px;
  border-top:2px solid var(--amber);background:var(--sand);border-radius:0 0 var(--r-card) var(--r-card);overflow:hidden}
.tp-meta>div,.tp-facts>div,.tp-zones>div{display:flex;gap:16px;padding:11px clamp(14px,2vw,20px);
  border-bottom:1px solid var(--line)}
.tp-meta>div:last-child,.tp-facts>div:last-child,.tp-zones>div:last-child{border-bottom:0}
.tp-meta dt,.tp-facts dt,.tp-zones dt{font-family:var(--mono);font-size:10px;letter-spacing:.16em;
  text-transform:uppercase;color:var(--grey);flex:0 0 38%;padding-top:3px}
.tp-meta dd,.tp-facts dd,.tp-zones dd{font-size:15.5px;color:var(--prose-strong);flex:1}
.tp-h{margin-top:clamp(30px,3.6vw,44px)}
.tp-gap{margin-top:14px;font-size:17px;color:var(--prose-strong)}
.tp-list{margin-top:12px;padding-left:20px;display:flex;flex-direction:column;gap:10px;color:var(--prose)}
.tp-list b{color:var(--prose-strong)}
.tp-foot{margin-top:20px;color:var(--grey)}

.tp-week{margin-top:16px;border:1px solid var(--line);border-radius:var(--r-card);overflow:hidden;
  break-inside:avoid;page-break-inside:avoid}
.tp-week>h3{display:flex;flex-wrap:wrap;align-items:baseline;gap:6px 14px;
  padding:11px clamp(14px,2vw,20px);background:var(--sand-2);border-bottom:1px solid var(--line)}
.tp-wn{font-family:var(--disp);font-weight:800;font-stretch:82%;text-transform:uppercase;font-size:17px;color:var(--ink)}
.tp-wp,.tp-wd{font-family:var(--mono);font-size:10px;letter-spacing:.14em;text-transform:uppercase;color:var(--grey)}
.tp-wk{margin-left:auto;font-family:var(--mono);font-size:11px;letter-spacing:.1em;color:var(--prose-strong)}
/* An easy week is marked by its words as well as its ground, because a
   background tint alone is not a label. */
.tp-week-easy>h3{background:var(--page)}
.tp-sess{list-style:none;margin:0}
.tp-sess li{display:flex;flex-direction:column;gap:3px;padding:11px clamp(14px,2vw,20px);
  border-bottom:1px solid var(--line);font-size:15.5px;color:var(--prose)}
.tp-sess li:last-child{border-bottom:0}
.tp-sess b{color:var(--prose-strong)}
@media(max-width:560px){
  .tp-meta>div,.tp-facts>div,.tp-zones>div{flex-direction:column;gap:2px}
  .tp-meta dt,.tp-facts dt,.tp-zones dt{flex:none}
}

/* -----------------------------------------------------------------
   TAP TARGETS ON A PHONE, in one block. Measured at 390px on 5 Sep 2026:
   every interactive element on fifteen pages, against the 44px Apple asks
   for. Nothing here changes a desktop, and nothing here moves a layout:
   where a control sits inline in a line of text, the hit area grows with
   padding and a matching negative margin, so the words around it stay put.
   The touch test is the one .upi-pay and .qmark already use.

   AT THE END OF THE FILE ON PURPOSE. Several of these controls set their own
   padding at the same specificity, and a rule that came earlier lost to
   them on source order alone: .gradelink stayed 16px tall while this block
   said otherwise. Last in the file, it wins the tie everywhere.

   The buttons: a .btn is 42px by design on a desktop and that is kept; on a
   phone one more pixel of padding either side takes it to 44 without any
   of the six scoped min-height rules this file had grown. */
@media(hover:none),(max-width:760px){
  .btn{padding-block:13px}
  /* The footer's currency chips and the theme toggle were 24px tall: fine
     under a mouse, not under a thumb. They sit centred and stacked here, so
     a full-height chip does not crowd the copyright beside it. */
  .base .curpick a{display:inline-flex;align-items:center;min-height:44px;padding:0 14px}
  .thpick button{min-height:44px;min-width:44px;padding:0 14px}
  /* Privacy and Terms: 14px of text, a 44px hit area, no change to the line. */
  .base .r a{display:inline-block;padding:15px 6px;margin:-15px -6px}
  /* The two "?" buttons that read as links. 16px of text; the rest is
     padding, cancelled by the margin so the paragraph does not grow. */
  .gradelink{padding-block:14px;margin-top:-2px;margin-bottom:-14px}
  .payplan-open{padding-block:14px;margin-top:2px;margin-bottom:-14px}
  /* The glance strip's links, 18px tall in a 34px band. */
  .marq-t a{display:inline-block;padding-block:13px;margin-block:-13px}
  /* "Also running" and "Details" links in the booking band, 28px lines. */
  .tbalist a,.linkish{display:inline-block;padding-block:8px;margin-block:-8px}
  /* Two small outlined controls on the tour page, 32 and 38px. */
  .week-toggle button,.itin-all{min-height:44px;display:inline-flex;align-items:center}
  /* Destination names in the month cards on the India hub, 24px lines. */
  .month a{display:inline-block;padding-block:14px;margin-block:-14px}
  /* Links that are the whole point of a row: a destination in a stacked
     table card, a hotel or airport in a spec strip. 20 to 24px lines. */
  .dtable-stack td a,.day-spec dd a,.tour-facts dd a{display:inline-block;padding-block:13px;margin-block:-13px}
  /* The blog: the category above a post's title, and the links in a
     sidebar panel, which were 16 and 20px lines. */
  .phero .kicker a{display:inline-block;padding-block:14px;margin-block:-14px}
  .pside-post li a{display:inline-block;padding-block:12px;margin-block:-12px}
  /* Close buttons: the popup's was 38px, the lightbox's arrows 42px wide. */
  .gh-x{width:44px;height:44px;top:6px;right:6px}
  .lb-nav{min-width:44px}
}

/* ---- ON PAPER ----------------------------------------------------
   The plan is meant to be saved as a PDF or printed and kept, which is
   what "downloadable" means on a site with no PDF library and no build
   step. So the site furniture goes: the nav, the footer, the buttons that
   only work on a screen, and every background tint, which on a domestic
   printer comes out as grey mud and costs a cartridge.

   A WEEK IS NEVER SPLIT ACROSS A PAGE. break-inside:avoid on .tp-week is
   the whole reason this block is worth having: a week torn in half between
   sheets is unreadable on a wall. */
@media print{
  /* THE LIGHT PALETTE, WHATEVER THE SCREEN WAS SET TO.

     This is the whole trick, and the first version did not do it. It named
     selectors one at a time and forced each to black, which left everything
     it had not thought of reading its colour from the dark theme: the
     headings, the kickers, the labels down the left of every panel, and the
     bold text in the lists all came out near white on white paper for any
     rider whose phone is set to dark. A printed page is ink on white and the
     tokens have to say so at the top, once, rather than being chased one
     rule at a time.

     BOTH DARK SELECTORS ARE NAMED because the site has two: the device
     setting, and the choice in the footer, which have to be able to beat one
     another on screen and must both lose here. --amber and --clay survive as
     themselves: they are hairlines and a few words, and they are the brand. */
  :root, :root:not([data-theme="light"]), :root[data-theme="dark"]{
    color-scheme:light;
    --page:#fff; --white:#fff; --sand:#fff; --sand-2:#fff;
    --ink:#000; --ink-2:#000; --prose-strong:#000;
    --prose:#222; --prose-soft:#444; --grey:#555;
    --line:#999; --line-d:#999;
  }
  @page{margin:14mm}
  html,body{background:#fff !important;color:#000 !important}
  /* The site furniture, and anything that only works under a finger. */
  /* The announcement bar, the back-to-top button and the skip link were not
     in this list, and the bar printed as a black strip across the top of
     page one, complete with the pulsing dot. Found on paper, 6 Sep 2026. */
  .nav,.tnav,footer,.noprint,.gh,.curdrop,.ann,.totop,.skip{display:none !important}
  .sec{padding:0 !important}
  .tplan .wrap{max-width:none;padding:0}
  a{color:#000 !important;text-decoration:none}
  /* Nobody can follow a link on paper, but they can read an address, so the
     one that matters is spelled out. mailto: already reads as its own text. */
  .tp-foot a::after{content:" (" attr(href) ")";font-size:11px}
  .tp-foot a[href^="mailto:"]::after{content:""}
  /* A WEEK IS NEVER TORN ACROSS TWO SHEETS. This is the reason the print
     block is worth having at all: half a week on a wall is unreadable. */
  .tp-week{break-inside:avoid;page-break-inside:avoid}
  .tp-h{margin-top:18px;break-after:avoid;page-break-after:avoid}
  .rv{opacity:1 !important;transform:none !important}
}


/* ---- Date of birth, as three boxes ----
   Replaced the native date field on /reserve/ on 30 Sep 2026: its year did
   not stop at four digits, it rolled, and a rider could not book. The note
   on the form in reserve.php has the measurements.

   A FIELDSET, so the three boxes are announced as one question. Browsers give
   a fieldset a border, padding and a min-content minimum width, and that last
   one is what lets a grid cell overflow on a phone, so all three go. It is
   display:block rather than inheriting .field's flex, because a legend inside
   a flex fieldset is laid out differently from browser to browser.

   The legend reads exactly like every other .field label. The Day, Month and
   Year labels are there for screen readers only: the DD / MM / YYYY in the
   boxes says the same thing on sight, and a second row of labels would push
   these boxes below the Gender select beside them. */
.dob{display:block;border:0;padding:0;margin:0 0 18px;min-width:0}
.dob>legend{font-family:var(--mono);font-size:10.5px;letter-spacing:.16em;text-transform:uppercase;
  color:var(--grey);margin-bottom:8px;padding:0}
.dob-parts{display:flex;gap:8px}
.dob-part{display:flex;flex-direction:column;min-width:0}
/* The year gets the room for four digits; day and month split what is left. */
.dob-d,.dob-m{flex:1 1 0}
.dob-y{flex:1.6 1 0}
.dob .dob-part label{position:absolute;width:1px;height:1px;overflow:hidden;
  clip-path:inset(50%);white-space:nowrap;margin:0}

/* ============================================================
   THE ADMIN SHELL, 22 Oct 2026.

   The panel stopped borrowing the public site's chrome on Sampath's
   instruction, and then stopped looking like a web page at all: it is laid
   out as a tool. A sidebar on a desktop and a tab bar along the bottom of a
   phone carry the sections; the content is cards on a tinted ground; the
   secondary forms live in popups opened from a list of actions, so a screen
   shows what is true and offers what can be done, and nothing explains
   itself at length. Every colour is a token from the set above, so the dark
   theme follows without a second set of rules.

   The ground is --sand in the light theme and the page colour in the dark
   one. Sand on dark would put the cards (--white, which goes darker) BELOW
   the ground, and a card that sinks reads as a hole. */
:root{--adm-ground:var(--sand);--adm-side-w:236px;--adm-bar-h:56px;--adm-tab-h:62px;--adm-ease:cubic-bezier(.22,1,.36,1)}
@media (prefers-color-scheme: dark){:root:not([data-theme="light"]){--adm-ground:var(--d-page)}}
:root[data-theme="dark"]{--adm-ground:var(--d-page)}
.adm-body{background:var(--adm-ground)}
.adm-body main{min-height:100vh}
.adm-wrap{max-width:1180px;margin:0 auto;padding-inline:clamp(18px,3.2vw,44px)}
.adm-main{padding:clamp(20px,3vw,36px) 0 clamp(36px,5vw,60px)}

/* THE SIDEBAR. Fixed to the left edge on a desktop; the content column
   is pushed over by its width. Dark on purpose, like the nav and footer
   of the public site, so it reads as the frame rather than as content. */
.adm-side-nav{position:fixed;top:0;bottom:0;left:0;width:var(--adm-side-w);z-index:20;
  display:flex;flex-direction:column;padding:18px 14px 16px;overflow-y:auto;
  background:var(--ink-surface);color:var(--on-ink);border-right:1px solid var(--line-d)}
.adm-brand{display:flex;align-items:center;gap:10px;padding:4px 10px 22px}
/* The global img rule is width:100%; the logo wants its own aspect. */
.adm-brand img{width:auto;height:30px}
.adm-brand span{font-family:var(--mono);font-size:10px;letter-spacing:.2em;text-transform:uppercase;
  color:var(--on-ink-soft);padding-left:10px;border-left:1px solid var(--line-d);line-height:1}
.adm-nav{display:flex;flex-direction:column;gap:2px}
.adm-nav a{position:relative;display:flex;align-items:center;gap:12px;padding:11px 12px;border-radius:var(--r);
  font-family:var(--mono);font-size:11.5px;letter-spacing:.12em;text-transform:uppercase;
  color:var(--on-ink-soft);transition:background .18s,color .18s}
.adm-nav a:hover{color:var(--on-ink);background:var(--ink-surface-2)}
/* The lit section: a square amber bar on its left edge, the same mark the
   public site's dark sections use, and a lifted ground. */
.adm-nav a[aria-current]{color:var(--on-ink);background:var(--ink-surface-2);box-shadow:inset 3px 0 0 var(--amber)}
.adm-nav a:focus-visible{outline-offset:-3px}
.adm-ico{width:18px;height:18px;flex:0 0 auto;fill:none;stroke:currentColor;stroke-width:1.8;
  stroke-linecap:round;stroke-linejoin:round}
/* The count on a section: UTRs to check, enquiries not yet answered.
   Amber because it means "look at this", the same as the chip. */
.adm-badge{display:inline-block;min-width:18px;height:18px;padding:0 5px;border-radius:9px;
  background:var(--amber);color:var(--on-accent);font-family:var(--mono);font-size:10.5px;font-weight:600;
  line-height:18px;text-align:center;letter-spacing:0;vertical-align:middle}
.adm-nav .adm-badge{margin-left:auto}
.adm-side-foot{margin-top:auto;padding:14px 10px 0;border-top:1px solid var(--line-d);
  display:flex;flex-wrap:wrap;gap:10px 8px;align-items:center}
.adm-user-name{flex:1 1 100%;font-family:var(--mono);font-size:11px;letter-spacing:.06em;color:var(--on-ink-soft)}
.adm-side-foot .btn{margin:0;padding:7px 10px;font-size:10.5px}

/* THE PHONE: a slim bar on top with the brand and the way out, a tab bar
   along the bottom with the four sections used most and a More sheet for
   the rest. The sidebar is not drawn at all. */
.adm-top{display:none}
.adm-tabbar{display:none}
@media(min-width:1000px){.adm-body main{padding-left:var(--adm-side-w)}}
@media(max-width:999px){
  .adm-side-nav{display:none}
  .adm-top{display:flex;position:sticky;top:0;z-index:20;align-items:center;justify-content:space-between;
    gap:12px;min-height:var(--adm-bar-h);padding-inline:var(--gut);
    background:var(--ink-surface);color:var(--on-ink);border-bottom:1px solid var(--line-d)}
  .adm-top .adm-brand{padding:0}
  .adm-top .adm-brand img{height:26px}
  .adm-top .btn{margin:0;padding:7px 10px;font-size:10.5px}
  .adm-body main{padding-bottom:calc(var(--adm-tab-h) + env(safe-area-inset-bottom, 0px))}
  .adm-tabbar{position:fixed;left:0;right:0;bottom:0;z-index:20;display:grid;grid-template-columns:repeat(5,1fr);
    background:var(--ink-surface);color:var(--on-ink);border-top:1px solid var(--line-d);
    padding-bottom:env(safe-area-inset-bottom, 0px)}
  .adm-tabbar a,.adm-tabbar button{position:relative;display:flex;flex-direction:column;align-items:center;
    justify-content:center;gap:5px;min-height:var(--adm-tab-h);padding:8px 2px 7px;border:0;background:none;
    font-family:var(--mono);font-size:9.5px;letter-spacing:.06em;text-transform:uppercase;
    color:var(--on-ink-soft);cursor:pointer;transition:color .18s}
  .adm-tabbar [aria-current],.adm-tabbar .is-on{color:var(--honey)}
  .adm-tabbar .adm-ico{width:22px;height:22px}
  .adm-tabbar .adm-badge{position:absolute;top:7px;left:calc(50% + 5px);min-width:16px;height:16px;
    line-height:16px;font-size:9.5px;padding:0 4px}
  .adm-tabbar a:focus-visible,.adm-tabbar button:focus-visible{outline-offset:-3px}
}

/* The page head: where you are, and the one thing you most often do here. */
.adm-ph{display:flex;flex-wrap:wrap;align-items:flex-end;justify-content:space-between;gap:12px 24px;
  margin-bottom:clamp(18px,2.4vw,26px)}
.adm-ph>div{min-width:0}
.adm-ph-back{display:inline-flex;align-items:center;gap:6px;margin-bottom:10px;font-family:var(--mono);
  font-size:11px;letter-spacing:.14em;text-transform:uppercase;color:var(--clay);transition:color .18s}
.adm-ph-back:hover,.adm-ph-back:focus-visible{color:var(--ink)}
.adm-title{font-family:var(--disp);font-weight:800;font-stretch:82%;text-transform:uppercase;
  font-size:clamp(26px,3vw,38px);line-height:1.02;letter-spacing:-.005em;margin:0;
  display:flex;flex-wrap:wrap;align-items:center;gap:6px 12px;overflow-wrap:anywhere}
.adm-title .adm-st{font-weight:400;letter-spacing:.1em}
.adm-ph-sub{margin:8px 0 0;font-family:var(--mono);font-size:12px;letter-spacing:.03em;color:var(--prose-soft);
  display:flex;flex-wrap:wrap;gap:4px 10px;align-items:center}
.adm-ph-sub a{color:var(--clay);transition:color .18s}
.adm-ph-sub a:hover{color:var(--ink)}
.adm-ph-act{display:flex;flex-wrap:wrap;gap:8px;align-items:center}
.adm-ph-act .btn,.adm-ph-act form{margin:0}

/* Notices sit on a sand ground here, so the sand panel they are on the
   public site would vanish into it. White, and a little tighter. */
.adm-main .notice{background:var(--white);margin:0 0 18px;padding:14px 18px;
  border:1px solid var(--line);border-top-width:3px;font-size:15px;line-height:1.5}
.adm-main .notice .adm-h{margin-bottom:6px}
.adm-main .notice p{margin-top:6px}

/* A TOAST for "that worked". Floats up from the bottom, says its one line,
   and goes away on its own; an error stays on the page as a notice,
   because an error has to be read. */
.adm-toast{position:fixed;left:50%;bottom:24px;z-index:30;transform:translateX(-50%);
  display:flex;align-items:center;gap:12px;max-width:min(560px,calc(100% - 32px));
  padding:12px 12px 12px 18px;border-radius:var(--r-card);
  background:var(--ink-surface);color:var(--on-ink);box-shadow:0 16px 44px rgba(25,19,16,.32);
  font-size:14.5px;line-height:1.45}
.adm-toast .adm-ico{width:18px;height:18px;color:var(--honey)}
.adm-toast p{margin:0}
.adm-toast button{width:32px;height:32px;flex:0 0 auto;border:0;border-radius:50%;background:transparent;
  color:var(--on-ink-soft);font-size:20px;line-height:1;cursor:pointer;display:grid;place-items:center;
  transition:background .18s,color .18s}
.adm-toast button:hover{background:var(--ink-surface-2);color:var(--on-ink)}
.adm-toast.is-gone{opacity:0;transform:translate(-50%,10px);transition:opacity .25s,transform .25s}
@media(max-width:999px){.adm-toast{bottom:calc(var(--adm-tab-h) + 16px + env(safe-area-inset-bottom, 0px))}}

/* THE CARD. One container for everything on the panel. A 3px amber rule
   on top marks the card that is the reason you opened the screen; clay
   marks the one that removes things. Both keep square shoulders, as the
   amber rules on .tour-facts and .notice do. */
.adm-card{background:var(--white);border:1px solid var(--line);border-radius:var(--r-card);
  padding:clamp(16px,2vw,22px);margin:0 0 16px}
.adm-card.is-primary{border-top:3px solid var(--amber);border-radius:0 0 var(--r-card) var(--r-card)}
.adm-card.is-danger{border-top:3px solid var(--clay);border-radius:0 0 var(--r-card) var(--r-card)}
.adm-card-h{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:8px 16px;margin-bottom:14px}
.adm-card-h .fine,.adm-card-h p{margin:0}
.adm-card-h .btn{margin:0;padding:7px 11px;font-size:10.5px}
/* Two controls in a card head sit on one line, level: an anchor and a
   button have different line boxes as inline text, and the waitlist's
   pair sat at two heights. Seen live, 22 Oct 2026. */
.adm-card-h .acts{display:flex;flex-wrap:wrap;gap:8px;align-items:center}
.adm-card-h .acts .btn{display:inline-flex;align-items:center;min-height:32px}
.adm-h{font-family:var(--disp);font-weight:800;font-stretch:82%;text-transform:uppercase;
  font-size:clamp(16.5px,1.5vw,19px);line-height:1.1;letter-spacing:0;margin:0}
.adm-h .adm-badge{margin-left:6px}
.adm-card .d3{font-size:clamp(16.5px,1.5vw,19px);line-height:1.1}
/* The one line a form gets, where it needs one at all: a rule the ledger
   depends on, or a figure the schedule suggests. Body face, not mono. */
.adm-hint{font-size:13.5px;line-height:1.5;color:var(--prose-soft);margin:0 0 14px;max-width:72ch}
.adm-hint b{color:var(--prose);font-weight:600}
.adm-hint code{font-family:var(--mono);font-size:12px;background:var(--sand);padding:1px 5px;border-radius:3px}
.adm-hint a{color:var(--clay)}
.adm-card>.adm-hint:last-child,.adm-card>form>.adm-hint:last-child{margin-bottom:0}
.adm-card form>.btn,.adm-card form>p>.btn,.adm-card form>.acts{margin-top:16px}
.adm-card form>.adm-row+.adm-hint,.adm-card form>.field+.adm-hint{margin-top:10px}
/* A card holding a table: the table runs edge to edge. */
.adm-card-flush{padding:0}
.adm-card-flush>.adm-card-h{padding:clamp(14px,1.8vw,18px) clamp(16px,2vw,22px) 0}
.adm-card-flush>.adm-hint{padding:0 clamp(16px,2vw,22px)}
.adm-card-flush>.tablewrap{margin:0}
.adm-card-flush>.adm-pager{margin:0;padding:14px clamp(16px,2vw,22px) 16px}
.adm-card-flush>p.fine{margin:0;padding:12px clamp(16px,2vw,22px) 16px}
.adm-card-flush>.adm-bulk{margin:clamp(14px,1.8vw,18px) clamp(16px,2vw,22px) 0}
.adm-card-flush>form>.adm-bulk{margin:clamp(14px,1.8vw,18px) clamp(16px,2vw,22px) 0}
.adm-empty{margin:0;padding:clamp(22px,3vw,34px);text-align:center;color:var(--prose-soft);font-size:14.5px}
.adm-empty a{color:var(--clay)}
@media(max-width:620px){
  /* Stacked rows are cards of their own under 620px (see .dtable-stack),
     and cards inside a card read as a mistake, so the outer one goes. */
  .adm-card-flush{background:none;border:0;border-radius:0;padding:0}
  .adm-card-flush>.adm-card-h,.adm-card-flush>.adm-hint,.adm-card-flush>p.fine,.adm-card-flush>.adm-pager{padding-inline:0}
  .adm-card-flush>.adm-card-h{padding-top:0}
  .adm-card-flush>.adm-bulk,.adm-card-flush>form>.adm-bulk{margin-inline:0}
  .adm-card-flush .adm-empty{background:var(--white);border:1px solid var(--line);border-radius:var(--r-card)}
}

/* STAT TILES. A label, a figure in the display face, a line under it.
   As a link where there is a list behind the number. */
.adm-stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(170px,1fr));gap:12px;margin:0 0 clamp(18px,2.4vw,26px)}
.adm-stat{display:block;background:var(--white);border:1px solid var(--line);border-radius:var(--r-card);
  padding:14px 16px 13px;color:inherit;min-width:0;transition:border-color .18s,transform .18s,box-shadow .18s}
a.adm-stat:hover{border-color:var(--amber);transform:translateY(-2px);box-shadow:0 8px 24px rgba(25,19,16,.08)}
.adm-stat.is-hot{border-top:3px solid var(--amber);border-radius:0 0 var(--r-card) var(--r-card)}
.adm-stat-l{display:block;font-family:var(--mono);font-size:10.5px;letter-spacing:.16em;text-transform:uppercase;color:var(--grey)}
.adm-stat-v{display:block;margin-top:8px;font-family:var(--disp);font-weight:800;font-stretch:82%;
  font-size:clamp(24px,2.4vw,32px);line-height:1;letter-spacing:-.005em;overflow-wrap:anywhere;font-variant-numeric:tabular-nums}
.adm-stat-v.is-money{font-size:clamp(18px,1.8vw,24px);line-height:1.15}
.adm-stat-s{display:block;margin-top:6px;font-family:var(--mono);font-size:11px;letter-spacing:.03em;color:var(--prose-soft)}
.adm-stats-sm{grid-template-columns:repeat(auto-fit,minmax(130px,1fr));gap:10px}
.adm-stats-sm .adm-stat{padding:11px 13px 10px}
.adm-stats-sm .adm-stat-v{font-size:clamp(18px,1.7vw,22px);margin-top:6px}
.adm-stats-sm .adm-stat-v.is-money{font-size:clamp(15px,1.4vw,18px);line-height:1.2}
@media(max-width:560px){.adm-stats{grid-template-columns:1fr 1fr;gap:10px}.adm-stats-sm{grid-template-columns:1fr 1fr 1fr}}
@media(max-width:380px){.adm-stats-sm{grid-template-columns:1fr 1fr}}

/* TABLES. Built on .dtable and the .dtable-stack phone rules, with the
   cell borders taken off: rules between rows only, a quiet head, a hover
   on the row. The first column stops being mono -- on the public tables
   it is a date, here it is a name. */
.adm-tbl{margin:0;font-size:14.5px}
.adm-tbl th,.adm-tbl td{border:0;border-bottom:1px solid var(--line);padding:12px clamp(12px,1.6vw,18px)}
.adm-tbl th{background:transparent;padding-top:14px;padding-bottom:10px}
.adm-tbl td:first-child{font-family:var(--body);font-size:14.5px;white-space:normal}
.adm-tbl tbody tr:last-child td{border-bottom:0}
.adm-tbl tbody tr{transition:background .15s}
.adm-tbl tbody tr:hover{background:var(--sand)}
.adm-tbl .fine{margin:2px 0 0}
.adm-tbl .adm-st{vertical-align:middle}
/* Cells whose wrapping only makes a short thing tall: a date, a count, a
   reference. Money is left to wrap, since two currencies can be long. */
.adm-tbl td.nw{white-space:nowrap}
/* A tour name: given room before the short columns squeeze it to a word a
   line. On a SPAN inside the cell, not on the cell: min-width on a <td>
   made Chrome paint that cell's collapsed border at its own content height,
   so the rule under Tour sat higher than the rule under the rest of the
   row. Seen live, 22 Oct 2026. */
.adm-tbl .wd{display:inline-block;min-width:200px;max-width:100%;vertical-align:top}
@media(max-width:620px){.adm-tbl .wd{min-width:0}}
.adm-tbl .btn{margin:0;padding:7px 11px;font-size:10.5px;white-space:nowrap}
.adm-tbl .acts{display:flex;gap:8px;align-items:center}
/* The link that opens a row: bold, and clay on hover. No underline, on
   Sampath's instruction (22 Oct 2026); nothing in the panel underlines,
   see the note at the end of this block. */
.adm-lnk{font-weight:600;transition:color .18s}
.adm-lnk:hover{color:var(--clay)}
@media(max-width:620px){
  .adm-tbl tbody tr:hover{background:var(--white)}
  .adm-tbl .acts{justify-content:flex-end}
}

/* The toolbar above a list: the status chips on the left, the search or
   the export on the right. The chips are white with a border here because
   the ground is sand and a sand chip on it would vanish. */
.adm-toolbar{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:10px 16px;margin:0 0 14px}
.adm-toolbar .adm-filter,.adm-toolbar .adm-export,.adm-toolbar .adm-search{margin:0}
.adm-toolbar .adm-search{flex:1 1 300px;max-width:460px}
.adm-toolbar-r{display:flex;flex-wrap:wrap;gap:8px;align-items:center}
.adm-toolbar-r .btn{margin:0}
.adm-search .btn{margin:0}
.adm-search input{height:44px;font-size:14.5px}
.adm-filterbar>.btn{min-height:44px}
@media(max-width:620px){
  /* On a phone the row of buttons under the search box pairs up two to a
     line, and so do the two pills on the right of the toolbar, instead of
     each taking a line of its own. */
  .adm-filterbar>.btn,.adm-filterbar>.adm-pill{flex:1 1 calc(50% - 5px)}
  .adm-toolbar-r{width:100%}
  .adm-toolbar-r>*{flex:1 1 calc(50% - 4px);min-width:0}
  .adm-toolbar-r .btn{width:100%;justify-content:center}
}
.adm-filter .gf{background:var(--white);border:1px solid var(--line);padding:7px 12px}
.adm-filter .gf:hover{background:var(--sand-2)}
.adm-filter .gf.on{background:var(--ink-surface);border-color:var(--ink-surface);color:var(--on-ink)}
/* A filter with nothing behind it is dimmed, not struck through. */
.adm-filter .gf.off{opacity:.45;text-decoration:none}
.adm-pager .gf{background:var(--white);border:1px solid var(--line)}
.adm-pager .gf.on{background:var(--ink-surface);border-color:var(--ink-surface);color:var(--on-ink)}
/* A pill button: an outlined .btn with a count on it, for the things a
   toolbar offers that are not the list itself. */
.adm-pill{display:inline-flex;align-items:center;gap:8px}
.adm-pill .adm-badge{margin:-2px 0}

/* ONE BOOKING: two columns on a desktop. The facts and the thing to do
   first on the left, with the money and the history under them; the
   rider's link and the list of actions on the right. On a phone it stacks
   in that order, which is the order it is needed in. */
.adm-cols{display:grid;grid-template-columns:minmax(0,1fr)}
@media(min-width:1000px){
  /* auto 1fr: the spare height lands in the second row, under the
     history, not between the facts and the history. */
  .adm-cols{grid-template-columns:minmax(0,1fr) 340px;grid-template-rows:auto 1fr;grid-template-areas:"a side" "b side";column-gap:20px;align-items:start}
  .adm-cols-a{grid-area:a}.adm-cols-b{grid-area:b}.adm-side{grid-area:side}
}
@media(min-width:1300px){.adm-cols{grid-template-columns:minmax(0,1fr) 380px}}
.adm-side .adm-card{margin-bottom:14px}
.adm-side .adm-link-url{flex:1 1 100%}
.adm-side .adm-link{margin:0 0 14px}
/* Facts, as label-over-value pairs in a grid, with no boxes around them. */
.adm-facts{display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:14px 18px;margin:0}
.adm-facts div{min-width:0}
.adm-facts dt{font-family:var(--mono);font-size:10px;letter-spacing:.16em;text-transform:uppercase;color:var(--grey);margin-bottom:3px}
.adm-facts dd{font-size:15px;font-weight:500;line-height:1.35;overflow-wrap:anywhere}
.adm-facts dd a{color:var(--clay)}

/* THE ACTIONS LIST. Each row is a button that opens the popup holding
   that form; the reminders switch sits among them as a row of its own. */
.adm-actlist{display:flex;flex-direction:column}
.adm-actlist>*{border-top:1px solid var(--line)}
.adm-actlist>*:first-child{border-top:0}
.adm-act-btn{display:flex;align-items:center;justify-content:space-between;gap:12px;width:100%;
  padding:13px 0;border:0;background:none;font-family:var(--body);font-size:15px;font-weight:500;
  color:var(--ink);text-align:left;cursor:pointer;transition:color .18s}
.adm-act-btn::after{content:"";flex:0 0 auto;width:8px;height:8px;border-right:1.5px solid currentColor;
  border-bottom:1.5px solid currentColor;transform:rotate(-45deg);opacity:.5;transition:transform .18s,opacity .18s}
.adm-act-btn:hover{color:var(--clay)}
.adm-act-btn:hover::after{transform:translateX(3px) rotate(-45deg);opacity:1}
.adm-act-btn.is-danger{color:var(--clay)}
.adm-act-btn.is-danger:hover{color:var(--ink)}
.adm-act-btn:focus-visible{outline-offset:-2px;border-radius:var(--r)}
.adm-actlist .adm-switch{padding:13px 0}
.adm-actlist .adm-switch>span:first-child{font-family:var(--body);font-size:15px;font-weight:500}
/* The switch slides now: the script flips it, then posts. */
.adm-switch-track,.adm-switch-track::after{transition:background .2s,left .2s var(--adm-ease)}

/* POPUPS. A native <dialog>, so Escape, focus and the backdrop are the
   browser's. Centred on a desktop; a sheet from the bottom on a phone. */
.adm-dlg{width:min(600px,calc(100% - 32px));max-height:min(88vh,900px);margin:auto;padding:0;
  border:1px solid var(--line);border-radius:var(--r-card);background:var(--white);color:var(--ink);
  box-shadow:0 24px 60px rgba(25,19,16,.28);overflow:auto;overscroll-behavior:contain}
.adm-dlg-wide{width:min(860px,calc(100% - 32px))}
.adm-dlg::backdrop{background:rgba(25,19,16,.48);backdrop-filter:blur(3px);-webkit-backdrop-filter:blur(3px)}
.adm-dlg-h{position:sticky;top:0;z-index:1;display:flex;align-items:center;justify-content:space-between;gap:16px;
  padding:16px 18px 12px 22px;background:var(--white);border-bottom:1px solid var(--line)}
.adm-dlg-b{padding:18px 22px 22px}
.adm-dlg-b>.adm-hint:first-child{margin-top:-2px}
.adm-dlg-b>form>.btn,.adm-dlg-b>form>.acts,.adm-dlg-b>form>p>.btn{margin-top:18px}
.adm-dlg-b .acts{display:flex;flex-wrap:wrap;gap:10px}
.adm-dlg-b .acts .btn{margin:0}
.adm-dlg-x{width:36px;height:36px;flex:0 0 auto;border:0;border-radius:50%;background:var(--sand);color:var(--ink);
  font-size:22px;line-height:1;cursor:pointer;display:grid;place-items:center;transition:background .18s,transform .18s}
.adm-dlg-x:hover{background:var(--line);transform:rotate(90deg)}
.adm-dlg .adm-addr,.adm-dlg .adm-emails-ta{width:100%;border:1px solid var(--line);border-radius:var(--r);
  padding:12px 14px;font-family:var(--mono);font-size:12.5px;line-height:1.7;
  background:var(--white);color:var(--ink);resize:vertical}
.adm-dlg .adm-copy{margin-top:12px;display:inline-flex;align-items:center;gap:8px}
/* The nested fields in a popup sit two to a row, three where it is wide. */
.adm-dlg .adm-row{grid-template-columns:repeat(auto-fit,minmax(170px,1fr));gap:16px 12px}
.adm-dlg .adm-row:not(:first-child){margin-top:16px}
.adm-dlg .field{margin-bottom:0}
.adm-dlg form>.field+.field,.adm-dlg form>.adm-row+.field,.adm-dlg form>.field+.adm-row{margin-top:16px}
@media(max-width:620px){
  .adm-dlg,.adm-dlg-wide{width:100%;max-width:100%;max-height:92vh;margin:auto 0 0;
    border-radius:var(--r-card) var(--r-card) 0 0;border-bottom:0}
  .adm-dlg-h{padding-top:22px}
  /* The grab-handle every sheet has, drawn rather than loaded. */
  .adm-dlg-h::before{content:"";position:absolute;top:8px;left:50%;width:36px;height:4px;margin-left:-18px;
    border-radius:2px;background:var(--line)}
  .adm-dlg-b{padding:16px 18px calc(22px + env(safe-area-inset-bottom, 0px))}
}

/* MOTION. All of it inside the no-preference guard, and all of it short:
   cards settle in as a screen opens, popups fade and lift, the toast rises.
   Added for the panel on Sampath's instruction, 22 Oct 2026; the public
   site's own set is unchanged. */
@media(prefers-reduced-motion:no-preference){
  @keyframes adm-in{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:none}}
  /* :not(dialog): the popups sit at the end of the column and have their
     own motion; with this animation on them as well, one opened while it
     was still running came up translucent. */
  .adm-main>.adm-wrap>*:not(.adm-stats):not(.adm-cols):not(dialog),.adm-stats>.adm-stat,
  .adm-cols-a>*:not(dialog),.adm-side>*,.adm-cols-b>*{animation:adm-in .45s var(--adm-ease) both}
  .adm-main>.adm-wrap>*:nth-child(2),.adm-stats>.adm-stat:nth-child(2),.adm-side>*:nth-child(1){animation-delay:.05s}
  .adm-main>.adm-wrap>*:nth-child(3),.adm-stats>.adm-stat:nth-child(3),.adm-cols-a>*:nth-child(2),.adm-side>*:nth-child(2){animation-delay:.1s}
  .adm-main>.adm-wrap>*:nth-child(4),.adm-stats>.adm-stat:nth-child(4),.adm-cols-b>*:nth-child(1){animation-delay:.15s}
  .adm-main>.adm-wrap>*:nth-child(5),.adm-stats>.adm-stat:nth-child(5),.adm-cols-b>*:nth-child(2){animation-delay:.2s}
  .adm-main>.adm-wrap>*:nth-child(6),.adm-stats>.adm-stat:nth-child(6){animation-delay:.25s}
  .adm-main>.adm-wrap>*:nth-child(n+7){animation-delay:.3s}
  @keyframes adm-toast{from{opacity:0;transform:translate(-50%,14px)}to{opacity:1;transform:translate(-50%,0)}}
  .adm-toast{animation:adm-toast .4s var(--adm-ease) both}
  /* The popup: opacity and a lift, both ways. @starting-style and
     allow-discrete are what let a display:none element animate in; a
     browser without them simply shows the popup at once. */
  .adm-dlg{opacity:0;transform:translateY(14px) scale(.985);
    transition:opacity .22s ease,transform .26s var(--adm-ease),overlay .26s allow-discrete,display .26s allow-discrete}
  .adm-dlg[open]{opacity:1;transform:none}
  @starting-style{.adm-dlg[open]{opacity:0;transform:translateY(14px) scale(.985)}}
  .adm-dlg::backdrop{opacity:0;transition:opacity .22s ease,overlay .26s allow-discrete,display .26s allow-discrete}
  .adm-dlg[open]::backdrop{opacity:1}
  @starting-style{.adm-dlg[open]::backdrop{opacity:0}}
  @media(max-width:620px){
    .adm-dlg{transform:translateY(40px)}
    @starting-style{.adm-dlg[open]{transform:translateY(40px)}}
  }
}

/* ONE ENQUIRY, tightened: the name is body weight rather than a display
   heading, the tick box sits in the name row, and the form is a row of
   smaller controls. */
.adm-lead{padding:clamp(14px,1.8vw,18px) clamp(14px,1.8vw,20px)}
.adm-lead-top{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.adm-lead-top .adm-pick{margin:0}
.adm-lead-name{font-family:var(--body);font-size:16.5px;font-weight:600;line-height:1.3;margin:0;text-transform:none;letter-spacing:0}
.adm-lead-main .fine{margin:4px 0 0 26px}
.adm-lead-msg{margin-top:10px;font-size:14.5px}
.adm-lead-form{margin-top:12px}
.adm-lead-form select,.adm-lead-form input{height:40px;font-size:14px}
.adm-lead-form .btn{padding:9px 14px}

/* The mail log as rows: when, how it went, what it was. */
.adm-log{margin:0;border:0;border-radius:0;padding:0;max-height:640px;background:transparent}
.adm-log div{display:grid;grid-template-columns:auto auto minmax(0,1fr);gap:0 12px;align-items:baseline;
  padding:7px clamp(12px,1.6vw,18px);white-space:normal;font-size:12px;line-height:1.5}
.adm-log div+div{border-top:1px solid var(--line)}
.adm-log time{color:var(--grey);white-space:nowrap}
.adm-log .adm-st{font-size:9.5px;padding:2px 7px}
.adm-log span{overflow-wrap:anywhere}
@media(max-width:560px){.adm-log div{grid-template-columns:auto auto}.adm-log span{grid-column:1 / -1}}

/* Sign in, as a card in the middle of the ground. */
.adm-login{max-width:400px;margin:clamp(24px,8vw,80px) auto;background:var(--white);
  border:1px solid var(--line);border-radius:var(--r-card);padding:clamp(22px,3vw,32px)}
.adm-login .kicker{margin-bottom:6px}
.adm-login .adm-title{margin-bottom:18px}
.adm-login .btn{margin-top:14px;width:100%}
.adm-login .notice{margin:0 0 16px}

/* The foot: a line, and the theme toggle. The toggle is the footer's
   control drawn on a light ground, so its borders and text come from the
   light ladder instead of the dark one. */
.adm-foot{background:var(--adm-ground);border-top:1px solid var(--line);padding:18px 0 26px;
  font-family:var(--mono);font-size:11px;letter-spacing:.06em;color:var(--prose-soft)}
/* The public stylesheet styles the bare footer tag dark; on the panel the
   foot is part of the content column, on the ground, and is pushed over
   by the sidebar the same way main is. Seen live, 22 Oct 2026, dark and
   half under the sidebar. */
@media(min-width:1000px){.adm-body .adm-foot{padding-left:var(--adm-side-w)}}
@media(max-width:999px){
  /* The tab bar is fixed over the bottom of the page; the foot carries the
     clearance for it rather than main, or the foot sits under the bar. */
  .adm-body main{padding-bottom:0}
  .adm-foot{padding-bottom:calc(26px + var(--adm-tab-h) + env(safe-area-inset-bottom, 0px))}
}
.adm-foot .adm-wrap{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:10px 18px}
.adm-foot .thpick{border-color:var(--line)}
.adm-foot .thpick button{color:var(--grey)}
.adm-foot .thpick button+button{border-left-color:var(--line)}
.adm-foot .thpick button:hover{color:var(--ink);background:var(--sand-2)}
.adm-foot .thpick button.is-on{color:var(--on-accent);background:var(--amber)}

/* The bulk bar sticks under the phone's top bar; on a desktop there is
   nothing above it to clear. */
.adm-bulk{top:8px}
@media(max-width:999px){.adm-bulk{top:calc(var(--adm-bar-h) + 8px)}}
/* Add a booking: the two groups are cards, so the form's own gaps go. */
.adm-manual .adm-card{margin-bottom:14px}
.adm-manual .acts{margin-top:4px}
.adm-import-help p{font-size:14px;line-height:1.55;color:var(--prose);margin:0 0 10px}
.adm-import-help p.fine{font-size:12px}
.adm-import label{margin-top:14px}

/* NO UNDERLINES ON THE PANEL'S LINKS. Sampath, 22 Oct 2026: the amber
   rules under every name and address looked wrong on a tool. Colour is
   the affordance instead: row links are bold and go clay on hover, and
   contact links are clay. This is a net under the rules above, so a
   public-site link style that reaches into the panel (.tlink, .prose a,
   .adm-lead-contact a) cannot put one back. */
/* :not(.btn):not(.gf) because a button-link and a chip are anchors too,
   and the net took the bottom edge off every outlined button-link on the
   panel -- Open beside Copy had three sides. Seen live, 22 Oct 2026. */
.adm-body main a:not(.btn):not(.gf),.adm-body .adm-foot a:not(.btn):not(.gf){text-decoration:none;border-bottom:0}
.adm-body .adm-lead-contact a,.adm-body .adm-tbl td a:not(.adm-lnk):not(.btn){color:var(--clay);transition:color .18s}
.adm-body .adm-lead-contact a:hover,.adm-body .adm-tbl td a:not(.adm-lnk):not(.btn):hover{color:var(--ink)}
