/* ==========================================================================
   Sabah Booking — brand content pages.
   Shared by the static/editorial pages: about, contact, faq, terms, esg,
   sitemap, testimonials, tips, tipsinfo, bookingProcedure, travelAlone,
   enquiry, weather, 404, 100.

   Loaded AFTER css/brand-home.css, which supplies the tokens and the shared
   brand shell (header, footer, buttons, cards, trust badge). This file adds
   ONLY what content pages need.

   The body carries "sb-home sb-page": `sb-home` is the brand shell scope that
   brand-home.css resets are written against, `sb-page` is this layer.

   Note brand-home.css zeroes margins on h1-h4/p and strips list styling from
   ul. Editorial copy needs those back, so `.sb-prose` re-establishes them for
   rich text (DB HTML and remote-fetched content) rather than fighting the
   reset page-wide.

   No !important anywhere: these pages do not load the legacy stylesheets.
   ========================================================================== */

/* A declared display value beats the `hidden` attribute's UA default, so any
   flex/grid component toggled via `hidden` would stay visible without this. */
.sb-page [hidden]{display:none}

/* ---- page hero ---------------------------------------------------------
   Replaces the legacy `hero_in bgN start_bg_zoom` banner. Same white
   protection gradient as the listing hero — never a dark scrim, so brand
   photography keeps its colour. Pages without a photo just omit the inline
   background-image and land on the sand wash. */
.sb-pagehero{
  position:relative;background-size:cover;background-position:center;
  background-color:var(--sand-100);
  padding:44px var(--gutter) 48px;
}
.sb-pagehero::before{
  content:"";position:absolute;inset:0;
  background:linear-gradient(100deg,
    rgba(255,255,255,.97) 0%,
    rgba(255,255,255,.92) 38%,
    rgba(255,255,255,.55) 68%,
    rgba(255,255,255,.15) 100%);
}
.sb-pagehero__inner{position:relative;z-index:2;max-width:720px}
.sb-pagehero h1{font:var(--text-h1);font-size:clamp(28px,3.4vw,40px)}
.sb-pagehero__sub{
  font:var(--text-subtitle);font-size:15px;color:var(--text-muted);margin-top:10px;
}
.sb-crumb{font:var(--text-caption);color:var(--text-muted)}
.sb-crumb a{color:var(--text-muted)}
.sb-crumb a:hover{color:var(--text-link)}
.sb-pagehero .sb-crumb{margin-bottom:8px}

/* ---- content scaffolding ----------------------------------------------- */
.sb-content{padding:48px var(--gutter)}
.sb-content--soft{background:var(--sand-100)}
.sb-content--tight{padding-top:32px;padding-bottom:32px}
.sb-content__inner{max-width:1180px;margin:0 auto}
/* editorial copy wants a shorter measure than the 1180 shell */
.sb-content__inner--narrow{max-width:820px}

.sb-pagehead{max-width:640px;margin:0 auto 32px;text-align:center}

/* Boki parked in the empty margin to the left of a centred .sb-pagehead. Absolute
   so the heading block keeps its own centring.
   Mobile-first on purpose: the 640px pagehead only leaves room for a 230px mascot
   once the viewport clears ~1260px, so below that Boki stays in normal flow above
   the heading (visible on phones) rather than being squeezed or hidden.
   Written as two-class selectors: a bare `.sb-content__boki` (0,1,0) would lose to
   brand-home.css's `.sb-home img{display:block}` (0,1,1). */
.sb-content--boki .sb-content__inner{position:relative}
.sb-content--boki .sb-content__boki{width:140px;height:auto;margin:0 auto 16px;pointer-events:none}
@media (min-width:1260px){
  .sb-content--boki .sb-content__boki{position:absolute;top:0;left:0;width:230px;margin:0}
}
.sb-pagehead h2{font:var(--text-h2)}
.sb-pagehead p{font:var(--text-subtitle);color:var(--text-muted);margin-top:8px}
.sb-pagehead--left{margin-left:0;text-align:left}

/* brandTrustPanel.jsp ships a Boki beside the panel, but the flex layout that
   places him lives in brand-detail.css — and shuttleinfo.jsp includes the
   fragment without loading that sheet, where he would otherwise drop in at his
   full 304x440 above the panel. Off by default, switched on by brand-detail.
   Scoped through the wrap so it outranks .sb-home img{display:block} (0,1,1). */
.sb-trustpanel-wrap .sb-trustpanel-wrap__mascot{display:none}

/* ---- prose / rich text -------------------------------------------------
   Scope for content this stylesheet does not author: DB article HTML and the
   remote-fetched terms/procedure text. brand-home.css strips margins and list
   markers globally, so they are restored here rather than page-wide. */
.sb-prose{font:var(--text-body);font-size:15px;color:var(--text-body-color)}
.sb-prose h1,.sb-prose h2,.sb-prose h3,.sb-prose h4{margin:28px 0 12px}
.sb-prose h2{font:var(--text-h2);font-size:22px}
.sb-prose h3{font:var(--text-h3)}
.sb-prose h4{font:var(--text-h4)}
.sb-prose > :first-child{margin-top:0}
.sb-prose p{margin:0 0 14px}
.sb-prose ul,.sb-prose ol{margin:0 0 14px;padding-left:22px}
.sb-prose ul{list-style:disc}
.sb-prose ol{list-style:decimal}
.sb-prose li{margin-bottom:6px}
.sb-prose a{color:var(--text-link);text-decoration:underline}
.sb-prose a:hover{color:var(--blue-600)}
.sb-prose img{max-width:100%;height:auto;border-radius:var(--radius-md);margin:12px 0}
/* CMS-authored prose HTML (route policies, terms, etc.) sometimes carries a
   legacy table with inline pixel widths on its <td>s (e.g. width:800px) from
   a desktop-era rich-text editor. `width:100%` alone doesn't stop that: an
   auto-layout table still grows to fit oversized cells, blowing the whole
   page out horizontally on mobile - which on a real phone can push a fixed-
   position sibling like #mobileBookBar's Book Now button off past the edge
   of the screen instead of just widening the table (found 2026-08-16 on a
   transferinfo "Private Car Charter" route's vehicle/pricing table).
   display:block+overflow-x:auto lets the table keep its authored column
   widths and become independently scrollable instead, containing the
   overflow - same technique as .sb-pricebar's horizontal scroll. */
.sb-prose table{display:block;overflow-x:auto;border-collapse:collapse;width:100%;margin:0 0 16px}
.sb-prose th,.sb-prose td{
  border:1px solid var(--border-subtle);padding:8px 10px;text-align:left;
}
.sb-prose strong,.sb-prose b{color:var(--text-heading)}
.sb-prose hr{border:0;border-top:1px solid var(--border-subtle);margin:24px 0}
/* The terms/procedure feed arrives as <br>-joined lines with no block
   elements, so give consecutive breaks a little air to fake paragraphing. */
.sb-prose br{line-height:2.1}

/* ---- feature cards -----------------------------------------------------
   Brand replacement for the legacy `box_feat` tile. Same shape as the
   homepage `.sb-why__card` but standalone (no sand band of its own), so a
   page can drop a grid of them into any section. */
.sb-feat__grid{display:grid;grid-template-columns:repeat(3,1fr);gap:20px}
.sb-feat__grid--2{grid-template-columns:repeat(2,1fr)}
.sb-feat__card{
  background:var(--surface-card);border-radius:var(--radius-lg);
  box-shadow:var(--shadow-card);padding:24px;text-align:center;
  display:block;color:inherit;
  transition:transform var(--dur-med) var(--ease-brand),
             box-shadow var(--dur-med) var(--ease-brand);
}
a.sb-feat__card:hover{transform:translateY(-2px);box-shadow:var(--shadow-float)}
.sb-feat__disc{
  width:48px;height:48px;border-radius:50%;background:var(--green-100);
  display:inline-flex;align-items:center;justify-content:center;
}
.sb-feat__disc .sb-icon{width:22px;height:22px;color:var(--green-600)}
.sb-feat__disc--blue{background:var(--blue-100)}
.sb-feat__disc--blue .sb-icon{color:var(--blue-600)}
.sb-feat__disc--coral{background:var(--coral-100)}
.sb-feat__disc--coral .sb-icon{color:var(--coral-600)}
.sb-feat__card h3{font:var(--text-h3);margin-top:12px}
.sb-feat__card p{font:var(--text-body);color:var(--text-body-color);margin-top:8px}

/* ---- duo: copy beside an image -----------------------------------------
   Named sb-duo, not sb-split: brand-home.css already owns `.sb-split` for the
   homepage journey band (display:flex plus a 40px/gutter padding). Reusing
   that name here would win on `display` but silently inherit the padding. */
.sb-duo{display:grid;grid-template-columns:1.15fr .85fr;gap:40px;align-items:center}
.sb-duo--flip > :first-child{order:2}
.sb-duo img{border-radius:var(--radius-lg);width:100%}
.sb-duo__stack{display:grid;grid-template-columns:1fr;gap:12px}
.sb-duo__stack img{aspect-ratio:4/3;height:auto;object-fit:cover}
.sb-duo__cap{font:var(--text-caption);color:var(--text-muted);margin-top:8px}

/* ---- B2B sign-in: login card beside the partner benefits -----------------
   Deliberately NOT built on .sb-duo/.sb-feat__grid, both of which are wrong
   here and are shared with about/esg/myAccount/review/weather:

     .sb-duo img{width:100%} is meant for editorial photography; it blew the
     50x50 benefit PNGs up to the column width, so they rendered soft and — as
     the three grid columns were not equal — at three different sizes.

     .sb-feat__grid uses repeat(3,1fr), and 1fr floors at auto, so a long word
     ("Competitive") widened its column and squeezed the others.

   Hence minmax(0,1fr) for genuinely equal columns, and a fixed image height
   so all six read as one set whatever their source dimensions. */
.sb-b2b{
  display:grid;grid-template-columns:minmax(0,400px) minmax(0,1fr);
  gap:40px;align-items:start;
}
.sb-b2b__why{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:16px}
.sb-b2b__tile{
  background:var(--surface-card);border-radius:var(--radius-lg);
  box-shadow:var(--shadow-card);padding:22px 14px;
  display:flex;flex-direction:column;align-items:center;gap:12px;text-align:center;
}
/* (0,1,1), same as `.sb-home img` — brand-page.css loads later, so this wins */
.sb-b2b__tile img{height:52px;width:auto;max-width:100%;object-fit:contain}
.sb-b2b__tile span{font:600 14px/1.4 var(--font-display);color:var(--text-heading)}
.sb-b2b__join{margin-top:20px;text-align:center}

@media (max-width:900px){
  .sb-b2b{grid-template-columns:minmax(0,1fr);gap:28px}
}
@media (max-width:520px){
  .sb-b2b__why{grid-template-columns:repeat(2,minmax(0,1fr))}
}

/* ---- pull quote --------------------------------------------------------- */
.sb-pullquote{
  background:var(--sand-100);border-left:3px solid var(--green-500);
  border-radius:var(--radius-md);padding:20px 24px;margin:24px 0;
  font:var(--text-subtitle);font-size:16px;line-height:1.6;color:var(--text-heading);
}
.sb-pullquote cite{
  display:block;margin-top:10px;
  font:var(--text-caption);font-style:normal;color:var(--text-muted);
}

/* ---- two-column article layout -----------------------------------------
   faq / tips / tipsinfo: sticky category rail beside the content column. */
.sb-withaside{display:grid;grid-template-columns:260px 1fr;gap:36px;align-items:start}
.sb-aside{position:sticky;top:84px}      /* clears the sticky brand header */
.sb-aside__card{
  background:var(--surface-card);border-radius:var(--radius-lg);
  box-shadow:var(--shadow-card);padding:20px;
}
.sb-aside__card + .sb-aside__card{margin-top:20px}
.sb-aside__card h3{font:var(--text-h4);margin-bottom:12px}
.sb-aside__nav{display:flex;flex-direction:column;gap:2px}
.sb-aside__nav a{
  display:flex;align-items:center;gap:8px;
  padding:8px 10px;border-radius:var(--radius-sm);
  font:var(--text-subtitle);color:var(--text-heading);
  transition:background var(--dur-fast) var(--ease-brand);
}
.sb-aside__nav a:hover{background:var(--gray-100)}
.sb-aside__nav a.is-active{background:var(--green-100);color:var(--green-800)}
.sb-aside__nav .sb-icon{width:16px;height:16px;color:var(--text-muted)}
.sb-aside__nav a.is-active .sb-icon{color:var(--green-600)}

/* ---- accordion (faq) ---------------------------------------------------
   Native <details>/<summary>: no JS, keyboard-accessible for free, and the
   legacy Bootstrap collapse ids (which collided across the two categories)
   stop being load-bearing. */
.sb-acc{display:flex;flex-direction:column;gap:10px}
.sb-acc__item{
  background:var(--surface-card);border:1px solid var(--border-subtle);
  border-radius:var(--radius-md);overflow:hidden;
}
.sb-acc__item[open]{box-shadow:var(--shadow-card);border-color:transparent}
.sb-acc__q{
  display:flex;align-items:center;justify-content:space-between;gap:16px;
  padding:16px 18px;cursor:pointer;list-style:none;
  font:var(--text-h4);color:var(--text-heading);
}
.sb-acc__q::-webkit-details-marker{display:none}
.sb-acc__q:hover{color:var(--green-600)}
.sb-acc__q .sb-icon{
  width:18px;height:18px;flex:none;color:var(--text-muted);
  transition:transform var(--dur-med) var(--ease-brand);
}
.sb-acc__item[open] .sb-acc__q .sb-icon{transform:rotate(180deg)}
.sb-acc__a{padding:0 18px 18px}

/* ---- link lists (sitemap, travelAlone, 404 recovery) -------------------- */
.sb-linklist{display:flex;flex-direction:column;gap:2px}
.sb-linklist a{
  display:flex;align-items:center;gap:10px;
  padding:11px 14px;border-radius:var(--radius-sm);
  font:var(--text-subtitle);font-size:15px;color:var(--text-heading);
  transition:background var(--dur-fast) var(--ease-brand);
}
.sb-linklist a:hover{background:var(--sand-100);color:var(--green-600)}
.sb-linklist .sb-icon{width:16px;height:16px;color:var(--green-600)}
.sb-linklist--cols{
  display:grid;grid-template-columns:repeat(2,1fr);gap:2px 24px;
}
/* numbered editorial list (travelAlone's top-10) */
.sb-ranklist{counter-reset:sbrank;display:flex;flex-direction:column;gap:2px}
.sb-ranklist a{
  display:flex;align-items:center;gap:12px;
  padding:11px 14px;border-radius:var(--radius-sm);
  font:var(--text-subtitle);font-size:15px;color:var(--text-heading);
  transition:background var(--dur-fast) var(--ease-brand);
}
.sb-ranklist a::before{
  counter-increment:sbrank;content:counter(sbrank);
  width:26px;height:26px;flex:none;border-radius:50%;
  background:var(--green-100);color:var(--green-800);
  display:inline-flex;align-items:center;justify-content:center;
  font:var(--text-small);font-weight:600;
}
.sb-ranklist a:hover{background:var(--sand-100)}

/* ---- article (tipsinfo) ------------------------------------------------- */
.sb-article__meta{
  display:flex;align-items:center;gap:16px;flex-wrap:wrap;
  font:var(--text-caption);color:var(--text-muted);
  padding-bottom:16px;margin-bottom:24px;
  border-bottom:1px solid var(--border-subtle);
}
.sb-article__meta span{display:inline-flex;align-items:center;gap:6px}
.sb-article__meta .sb-icon{width:14px;height:14px}
.sb-article__share{
  display:flex;align-items:center;gap:12px;flex-wrap:wrap;
  margin-top:32px;padding-top:20px;border-top:1px solid var(--border-subtle);
}
.sb-article__share > span{font:var(--text-subtitle);font-weight:600;color:var(--text-heading)}
.sb-photostrip{display:grid;grid-template-columns:repeat(2,1fr);gap:8px}
.sb-photostrip img{width:100%;height:88px;object-fit:cover;border-radius:var(--radius-sm)}

/* ---- testimonial tiles -------------------------------------------------
   Replaces the legacy `view view-tenth` hover mask, which hid the quote until
   hover — the text is the point, so it is always visible now. */
.sb-quotes{display:grid;grid-template-columns:repeat(4,1fr);gap:20px}
.sb-quotecard{
  background:var(--surface-card);border-radius:var(--radius-lg);
  box-shadow:var(--shadow-card);overflow:hidden;display:flex;flex-direction:column;
}
.sb-quotecard img{width:100%;height:180px;object-fit:cover}
.sb-quotecard__body{padding:16px;display:flex;flex-direction:column;gap:8px;flex:1}
.sb-quotecard__text{font:var(--text-body);color:var(--text-body-color)}
.sb-quotecard__by{
  font:var(--text-caption);color:var(--text-muted);margin-top:auto;padding-top:8px;
}

/* ---- info list (contact) ------------------------------------------------ */
.sb-infolist{display:flex;flex-direction:column;gap:20px}
.sb-infoitem{display:flex;gap:14px;align-items:flex-start}
.sb-infoitem__disc{
  width:40px;height:40px;flex:none;border-radius:50%;background:var(--blue-100);
  display:inline-flex;align-items:center;justify-content:center;
}
.sb-infoitem__disc .sb-icon{width:18px;height:18px;color:var(--blue-600)}
.sb-infoitem h4{font:var(--text-h4);margin-bottom:4px}
.sb-infoitem p,.sb-infoitem a{font:var(--text-body);color:var(--text-body-color)}
.sb-infoitem a:hover{color:var(--text-link)}
.sb-map{
  width:100%;height:380px;border:0;border-radius:var(--radius-lg);
  box-shadow:var(--shadow-card);
}

/* ---- form --------------------------------------------------------------- */
.sb-form{
  background:var(--surface-card);border-radius:var(--radius-lg);
  box-shadow:var(--shadow-card);padding:28px;
}
.sb-form__grid{display:grid;grid-template-columns:1fr 1fr;gap:16px}
.sb-field{display:flex;flex-direction:column;gap:6px}
.sb-field--full{grid-column:1 / -1}
.sb-field label{font:var(--text-subtitle);font-weight:600;color:var(--text-heading)}
.sb-field input,.sb-field textarea,.sb-field select{
  font:var(--text-body);font-size:15px;color:var(--text-heading);
  padding:11px 13px;border:1px solid var(--gray-300);
  border-radius:var(--radius-md);background:var(--surface-page);
  width:100%;font-family:var(--font-body);
  transition:border-color var(--dur-fast) var(--ease-brand);
  /* `<select>` ignores the shorthand `font`'s line-height the way `<input>`
     doesn't (a native-rendering quirk, not a CSS override anywhere in this
     file) and comes out a few px shorter, so a date input and its Time
     select in the same .sb-bookbox__grid row sat at different heights and
     didn't line up. An explicit height pins both to the same box regardless
     of how each control wants to size itself; textarea's own min-height:130px
     rule below still wins over this since min-height beats a smaller height. */
  height:48px;
}
.sb-field input:focus,.sb-field textarea:focus,.sb-field select:focus{
  border-color:var(--blue-500);outline:none;box-shadow:0 0 0 3px var(--blue-100);
}
.sb-field textarea{min-height:130px;resize:vertical}
.sb-field__err{font:var(--text-caption);color:var(--coral-600);display:none}
.sb-field.is-invalid input,.sb-field.is-invalid textarea{border-color:var(--coral-500)}
.sb-field.is-invalid .sb-field__err{display:block}
.sb-form__foot{display:flex;align-items:center;gap:14px;margin-top:20px}
.sb-form__note{font:var(--text-caption);color:var(--text-muted)}
.sb-btn[disabled]{opacity:.6;cursor:default}

/* ---- account / credential forms -----------------------------------------
   login, register, express signup, profile, change password. Nothing here is
   auth-specific logic: it is the small set of shapes the legacy pages got
   from bootstrap (full-width submit, checkbox row, inline link button) plus
   the password reveal control the old pages built out of an icon font. */

/* the credential forms are single-column and much narrower than the 820px
   editorial measure, or the inputs stretch to an absurd line length */
.sb-authcard{max-width:460px;margin:0 auto}

/* Boki peeking out from behind the card's top-right corner, not sitting
   flat on top of it. `.sb-authcard .sb-form` (scoped here, not the shared
   `.sb-form` rule above) gets its own stacking context via position+z-index,
   so the mascot — a child of it with z-index:-1 — paints behind the card's
   own background/shadow instead of the whole page: the half that overlaps
   the card hides behind it, the half poking out above stays visible.
   No transform or filter: either one forces the browser to resample the
   image, which is what was reading as blurry — not the source resolution. */
.sb-authcard .sb-form{position:relative;z-index:0;overflow:visible}
.sb-authcard__boki{
  position:absolute;z-index:-1;top:-104px;right:24px;
  display:block;height:190px;width:auto;
  pointer-events:none;
}

.sb-btn--block{width:100%;justify-content:center;padding:12px 20px}

/* password reveal. The wrapper (not .sb-field) is the positioning context so
   the button sits against the input whether or not an error line is present. */
.sb-pw{position:relative;display:flex}
.sb-pw input{padding-right:44px}
.sb-pw__eye{
  position:absolute;top:50%;right:8px;transform:translateY(-50%);
  display:flex;align-items:center;justify-content:center;
  width:28px;height:28px;padding:0;border:0;border-radius:var(--radius-sm);
  background:transparent;color:var(--gray-500);cursor:pointer;
}
.sb-pw__eye:hover{color:var(--text-heading);background:var(--gray-100)}
.sb-pw__eye .sb-icon{width:18px;height:18px}

/* inline text control (the "forgot your password?" trigger) */
.sb-linkish{
  background:none;border:0;padding:0;cursor:pointer;
  font:var(--text-caption);color:var(--text-link);text-decoration:underline;
}
.sb-linkish:hover{color:var(--blue-600)}

/* one-line status text written by script into a placeholder span */
.sb-note{font:var(--text-caption)}
.sb-note--ok{color:var(--green-600)}
.sb-note--bad{color:var(--coral-600)}

/* label + value rows (promotional code result) */
.sb-deflist{display:grid;grid-template-columns:auto 1fr;gap:10px 20px}
.sb-deflist dt{font:var(--text-subtitle);font-weight:600;color:var(--text-muted)}
.sb-deflist dd{font:var(--text-body);color:var(--text-heading)}

/* ---- titled detail group (myBooking) ------------------------------------
   A booking carries ~30 term/value pairs. Run as one list they read as an
   undifferentiated wall, and the old two-column split cut across meaning —
   payment ended up in the left column and the pickup arrangements in the
   right. These group the pairs by what a member is actually looking for:
   contact / arrangement / payment / documents.

   The heading is what does the work; the rule under it just stops two
   adjacent groups from reading as one list. */
.sb-dgroup + .sb-dgroup{margin-top:28px}
/* .sb-acc__a opens with no top padding, so the first group's underlined
   heading would sit flush against the "Details" summary and read as part
   of it rather than as the first section inside it. */
.sb-acc__a > .sb-dgroup:first-child{margin-top:8px}
/* 16px/700 against the 14px/600 labels below it. At the labels' own size the
   heading stopped reading as a heading at all — it just looked like another
   term with nothing beside it. */
.sb-dgroup > h4{
  font:var(--text-h4);font-weight:700;color:var(--text-heading);
  padding-bottom:8px;margin-bottom:14px;
  border-bottom:1px solid var(--border-subtle);
}

/* Two term/value pairs per row. The columns are declared on the <dl> itself
   so plain <dt>/<dd> children auto-flow into them — no per-row wrapper, which
   means the JSP keeps emitting the same flat list it always did.

   `max-content` on the label columns rather than `auto`: `auto` lets a long
   value in one row widen the label column for every other row, which is what
   made the labels drift away from their values. */
.sb-deflist--pairs{
  grid-template-columns:max-content minmax(0,1fr) max-content minmax(0,1fr);
  gap:12px 18px;
}
/* values wrap instead of forcing the grid wider than the card */
.sb-deflist--pairs dd{min-width:0;overflow-wrap:anywhere}
/* An unfilled optional field (no WhatsApp, no drop-off) reads as a rendering
   fault when it is simply blank. A dash says "nothing here" out loud.
   :empty deliberately does not match the AJAX placeholders (confirmation
   slip, invoice, bank slip) — those hold a <span>, so they keep their
   spinner and get filled in later. */
.sb-deflist--pairs dd:empty::after{content:"—";color:var(--text-muted)}
/* the two figures a member opens this panel to check */
.sb-deflist--pairs dd.sb-deflist__key{font-weight:700}

/* 1200px, not the 900px the rest of the page switches at: this list sits in
   the .sb-withaside content column, which is ~260px narrower than the
   viewport. Below this the second value column is too narrow to hold an
   address without wrapping every line. */
@media (max-width:1200px){
  .sb-deflist--pairs{grid-template-columns:max-content minmax(0,1fr)}
}
@media (max-width:520px){
  /* below this the label column starves the value column, so stack them */
  .sb-deflist--pairs{grid-template-columns:minmax(0,1fr);gap:2px 0}
  .sb-deflist--pairs dt{margin-top:10px}
  .sb-deflist--pairs dt:first-child{margin-top:0}
}

/* a long form split into titled blocks, separated by a rule (feedback) */
.sb-formsec + .sb-formsec{
  margin-top:28px;padding-top:24px;border-top:1px solid var(--border-subtle);
}
/* 4px put the heading right on top of the first label. A checkout form is
   read section by section, so each heading needs to own its block. */
.sb-formsec > h2{font:var(--text-h3);margin-bottom:18px}
.sb-formsec > h3{font:var(--text-h4);margin-bottom:4px}

/* ---- star rating -------------------------------------------------------
   Replaces the sky-forms `.rating` widget. The radios stay in the page's
   original descending order (5 -> 1) because their ids/values are the wire
   contract; `flex-direction:row-reverse` puts them back on screen as 1 -> 5,
   which is also what makes the sibling combinator work: the checked (or
   hovered) input is followed in the DOM by every LOWER star, i.e. every star
   to its left. Hover only ever adds fill, never removes it — same as the
   legacy widget. */
.sb-rate{display:flex;align-items:center;gap:16px;flex-wrap:wrap;padding:9px 0}
.sb-rate__label{font:var(--text-subtitle);color:var(--text-heading)}
.sb-rate__stars{
  position:relative;
  display:inline-flex;flex-direction:row-reverse;justify-content:flex-end;gap:4px;
}
.sb-rate__stars input{position:absolute;width:1px;height:1px;opacity:0}
.sb-rate__stars label{display:inline-flex;cursor:pointer;color:var(--gray-300)}
.sb-rate__stars label .sb-icon{width:26px;height:26px;fill:currentColor}
.sb-rate__stars input:checked ~ label{color:var(--star)}
.sb-rate__stars label:hover,
.sb-rate__stars label:hover ~ label{color:var(--star)}
.sb-rate__stars input:focus-visible + label{
  outline:2px solid var(--focus-ring);outline-offset:2px;border-radius:var(--radius-sm);
}

/* ---- checkbox / radio choices ------------------------------------------ */
.sb-check{
  display:flex;align-items:center;gap:9px;cursor:pointer;
  font:var(--text-body);font-size:15px;color:var(--text-body-color);
}
.sb-check input{
  width:17px;height:17px;flex:none;cursor:pointer;accent-color:var(--green-600);
}
.sb-checks{display:grid;grid-template-columns:repeat(2,1fr);gap:9px 20px}
/* a question with its yes/no pair on one line */
.sb-choicerow{
  display:flex;align-items:center;justify-content:space-between;
  gap:16px;flex-wrap:wrap;padding:9px 0;
}
.sb-choicerow__q{font:var(--text-subtitle);color:var(--text-heading)}
.sb-choices{display:flex;gap:22px}

/* ---- enquiry box: WhatsApp / email tabs ---------------------------------
   Mirrors helpBox2.jsp, which the detail pages used before the conversion.
   WhatsApp is the default and the primary channel — it is how most Malaysian
   guests actually reach us — so it leads and carries the green. */
.sb-helpbox{
  background:var(--green-100);border:1px solid var(--green-300);
  border-radius:var(--radius-lg);padding:24px;
}
.sb-helpbox__head{
  display:flex;align-items:center;justify-content:space-between;gap:14px;
  flex-wrap:wrap;margin-bottom:14px;
}
.sb-helpbox__title{display:flex;align-items:center;gap:12px}
.sb-helpbox__disc{
  width:42px;height:42px;flex:none;border-radius:50%;
  background:var(--green-600);color:var(--text-inverse);
  display:flex;align-items:center;justify-content:center;
}
.sb-helpbox__disc .sb-icon{width:22px;height:22px}
.sb-helpbox__title h2{font:var(--text-h3);color:var(--green-800)}
.sb-helptabs{
  display:inline-flex;border:2px solid var(--green-600);
  border-radius:var(--radius-sm);overflow:hidden;
}
.sb-helptabs button{
  display:flex;align-items:center;gap:6px;
  padding:8px 16px;border:0;cursor:pointer;
  font:var(--text-subtitle);font-weight:600;
  background:transparent;color:var(--green-600);
  transition:background var(--dur-fast) var(--ease-brand),
             color var(--dur-fast) var(--ease-brand);
}
.sb-helptabs button .sb-icon{width:15px;height:15px}
.sb-helptabs button[aria-selected="true"]{background:var(--green-600);color:var(--text-inverse)}
.sb-helpbox__intro{font:var(--text-body);color:var(--text-body-color)}
.sb-helpbox__note{
  display:flex;align-items:center;gap:7px;
  font:var(--text-caption);color:var(--text-muted);margin-top:6px;
}
.sb-helpbox__note .sb-icon{width:14px;height:14px;color:var(--green-600)}
.sb-helpbox__note--block{align-items:flex-start;line-height:1.55;margin-top:22px}
.sb-helpbox__note--block .sb-icon{flex-shrink:0;margin-top:3px}
.sb-helpbox__panel{margin-top:16px}
.sb-helpbox__panel[hidden]{display:none}
.sb-helpbox__foot{
  display:flex;align-items:center;gap:16px;flex-wrap:wrap;margin-top:16px;
}
/* WhatsApp keeps its own brand colour — a green button here is not our green */
.sb-btn--wa{background:#25D366;color:#fff;border-radius:var(--radius-md);padding:12px 24px}
.sb-btn--wa:hover{background:#1EBE5A}
.sb-helpbox .sb-form{box-shadow:none;border:1px solid var(--border-subtle);padding:20px}

/* ---- modal ---------------------------------------------------------------
   Replaces the Bootstrap dialog the member pages used for booking
   cancellation. `data-bs-toggle="modal"` needs Bootstrap's JS, which brand
   pages do not load — so that button silently did nothing and a member could
   not cancel a booking at all. Built on native <dialog>: it gets focus
   trapping, Escape-to-close and the top layer for free.

   Open with dlg.showModal(), close with dlg.close(). */
.sb-modal{
  border:0;padding:0;max-width:min(460px,92vw);width:100%;
  border-radius:var(--radius-lg);box-shadow:var(--shadow-float);
  background:var(--surface-card);color:var(--text-body-color);
}
.sb-modal::backdrop{background:rgba(17,17,17,.55)}
.sb-modal__head{
  display:flex;align-items:flex-start;gap:12px;
  padding:20px 22px 0;
}
.sb-modal__head h3{font:var(--text-h3);font-size:18px;flex:1}
.sb-modal__disc{
  width:38px;height:38px;flex:none;border-radius:50%;
  background:var(--coral-100);display:flex;align-items:center;justify-content:center;
}
.sb-modal__disc .sb-icon{width:19px;height:19px;color:var(--coral-600)}
.sb-modal__body{padding:14px 22px 0;font:var(--text-body);font-size:15px}
.sb-modal__foot{
  display:flex;justify-content:flex-end;gap:10px;flex-wrap:wrap;
  padding:20px 22px 22px;
}
.sb-btn--danger{background:var(--coral-500);color:var(--text-inverse);border-radius:var(--radius-md)}
.sb-btn--danger:hover{background:var(--coral-600)}
.sb-btn--quiet{background:var(--gray-100);color:var(--text-heading);border-radius:var(--radius-md)}
.sb-btn--quiet:hover{background:var(--gray-300)}
/* Destructive, but only the TRIGGER — the "Cancel Booking" that opens the
   confirm dialog. Solid coral (.sb-btn--danger) is kept for the confirm
   button inside that dialog, where cancelling really is the one thing the
   screen is asking for. On the booking panel it is not: a member who has
   already paid sees no Pay button, so a solid coral Cancel became the
   loudest thing on the page. Coral is capped at one per screen. */
.sb-btn--dangerquiet{
  background:var(--gray-100);color:var(--coral-600);border-radius:var(--radius-md);
}
.sb-btn--dangerquiet:hover{background:var(--coral-100);color:var(--coral-800)}

/* busy indicator for in-page uploads — the legacy pages used an icon font
   (icon-spin6 animate-spin) that brand pages no longer load. */
.sb-spin{
  display:inline-block;width:16px;height:16px;vertical-align:-3px;
  border:2px solid var(--gray-300);border-top-color:var(--green-600);
  border-radius:50%;animation:sb-spin .8s linear infinite;
}
@keyframes sb-spin{to{transform:rotate(360deg)}}
@media (prefers-reduced-motion:reduce){
  .sb-spin{animation-duration:2.4s}
}

/* ---- alerts ------------------------------------------------------------- */
.sb-alert{
  display:flex;gap:12px;align-items:flex-start;
  padding:16px 18px;border-radius:var(--radius-md);
  font:var(--text-body);font-size:15px;
}
.sb-alert .sb-icon{width:20px;height:20px;flex:none}
.sb-alert--ok{background:var(--green-100);color:var(--green-800)}
.sb-alert--ok .sb-icon{color:var(--green-600)}
.sb-alert--bad{background:var(--coral-100);color:var(--coral-800)}
.sb-alert--bad .sb-icon{color:var(--coral-600)}
.sb-alert--info{background:var(--blue-100);color:var(--blue-800)}
.sb-alert--info .sb-icon{color:var(--blue-600)}

/* ---- data table (weather) ----------------------------------------------- */
.sb-tablewrap{overflow-x:auto;border-radius:var(--radius-lg);box-shadow:var(--shadow-card)}
.sb-table{border-collapse:collapse;width:100%;min-width:640px;background:var(--surface-card)}
.sb-table caption{
  caption-side:top;text-align:left;padding:16px 18px 12px;
  font:var(--text-h3);color:var(--text-heading);
}
.sb-table th,.sb-table td{
  padding:11px 14px;text-align:center;font:var(--text-body);
  border-bottom:1px solid var(--border-subtle);
}
.sb-table thead th{
  background:var(--sand-100);font:var(--text-subtitle);font-weight:600;
  color:var(--text-heading);white-space:nowrap;
}
/* row-header column: the day/metric label down the left edge */
.sb-table tbody th{
  background:var(--sand-100);text-align:left;white-space:nowrap;
  font:var(--text-subtitle);font-weight:600;color:var(--text-heading);
}
.sb-table tbody tr:last-child th,.sb-table tbody tr:last-child td{border-bottom:0}
.sb-table__today{color:var(--green-800)}

/* ---- booking card (myBooking) -------------------------------------------
   One booking used to render as two floating panels: a shadow-only
   .sb-tablewrap and, 14px below it, a bordered <details>. Nothing tied them
   together, so with several bookings listed it was not obvious which "Details"
   belonged to which code. They are now one outlined card, and the code and
   status move out of the table into the card's own head — which also drops the
   table from four columns to two and lets the tour name breathe.

   The outline is --sand-600 rather than --border-subtle: subtle is right for a
   rule *inside* a panel, but too faint to read as the edge of one against a
   white page. */
.sb-bk{
  background:var(--surface-card);
  border:1px solid var(--sand-600);border-radius:var(--radius-lg);
  overflow:hidden;box-shadow:var(--shadow-card);
  margin-bottom:20px;
}
.sb-bk__head{
  display:flex;align-items:center;justify-content:space-between;gap:16px;
  flex-wrap:wrap;padding:14px 18px;
  background:var(--sand-100);border-bottom:1px solid var(--border-subtle);
}
.sb-bk__code{font:var(--text-h4);color:var(--text-heading)}
.sb-bk__code small{
  display:block;margin-bottom:2px;
  font:var(--text-caption);color:var(--text-muted);
}
/* the panes inside give up their own frame — the card is the frame now */
.sb-bk .sb-tablewrap{border-radius:0;box-shadow:none}
.sb-bk .sb-acc__item{border:0;border-top:1px solid var(--border-subtle);border-radius:0}
.sb-bk .sb-acc__item[open]{box-shadow:none}
/* header row reads as a label strip, not a second banded block under the
   already-sand card head */
.sb-bk .sb-table thead th{background:transparent}
/* the name column's cell is left-aligned; with only two columns left, a
   centred heading above it reads as a mis-alignment rather than a style */
.sb-bk .sb-table thead th:first-child{text-align:left}
/* the shared 640px floor exists for the four-to-six column weather/listing
   tables. Two columns fit a phone, so it would only force a pointless
   sideways scroll here. */
.sb-bk .sb-table{min-width:0}

.sb-bk__status{
  display:inline-flex;align-items:center;gap:6px;white-space:nowrap;
  padding:4px 12px;border-radius:var(--radius-pill);
  font:600 13px/1.4 var(--font-display);
}
/* parseStatus() is shared with b2b/cp/e-mail and still wraps its label in
   <font color> / <b>. A presentational attribute loses to any author rule, so
   handing the colour back to the pill needs no !important and no change to
   that helper. */
.sb-bk__status font,.sb-bk__status b{color:inherit;font-weight:inherit}
.sb-bk__status--ok{background:var(--green-100);color:var(--green-800)}      /* confirmed, installment running */
.sb-bk__status--wait{background:var(--blue-100);color:var(--blue-800)}      /* processing, checking, awaiting approval */
.sb-bk__status--warn{background:var(--coral-100);color:var(--coral-800)}    /* needs the member to act */
.sb-bk__status--off{background:var(--gray-100);color:var(--gray-500)}       /* cancelled, closed, discarded */

/* ---- key / value card (bankDetail) --------------------------------------
   Replaces the legacy `tag-box tag-box-vN` panel. A <dl>, because these rows
   really are term/definition pairs — and the account number wraps rather than
   pushing the card wide on a phone. */
.sb-kv{
  background:var(--surface-card);border-radius:var(--radius-lg);
  box-shadow:var(--shadow-card);padding:8px 24px;
}
.sb-kv__row{
  display:flex;align-items:baseline;justify-content:space-between;gap:16px;
  padding:14px 0;border-bottom:1px solid var(--border-subtle);
}
.sb-kv__row:last-child{border-bottom:0}
.sb-kv dt{font:var(--text-subtitle);color:var(--text-muted)}
.sb-kv dd{
  font:var(--text-h4);font-size:17px;color:var(--text-heading);
  text-align:right;overflow-wrap:anywhere;
}
.sb-kv .sb-kv__amount{color:var(--blue-600)}
.sb-kv .sb-kv__due{color:var(--coral-600)}

/* ---- error pages (404, 100) --------------------------------------------- */
.sb-error{
  min-height:60vh;display:flex;align-items:center;justify-content:center;
  padding:64px var(--gutter);background:var(--sand-100);text-align:center;
}
.sb-error__inner{max-width:560px}
.sb-error__code{
  font:600 96px/1 var(--font-display);color:var(--green-500);letter-spacing:-2px;
}
.sb-error h1{font:var(--text-h2);margin-top:12px}
.sb-error p{font:var(--text-body);font-size:15px;color:var(--text-muted);margin-top:10px}
.sb-error img{margin:0 auto 20px;max-height:150px;width:auto}
.sb-error .sb-linklist{
  max-width:320px;margin:24px auto 0;text-align:left;
}
.sb-error__cta{margin-top:24px;display:inline-flex}

/* ---- checkout (bookCar and its bookTour/bookHoliday/… siblings) ----------
   The last step of the funnel. One column: the progress strip, then the
   summary card so the guest can check what they are paying for before filling
   anything in, then the form as numbered .sb-formsec blocks.

   `label.error` is generated by jQuery Validate, which these pages keep — the
   rule set (payMethod, terms, …) is part of the server contract and could not
   be swapped for native validation. Its errorPlacement inserts the label after
   the field WRAPPER, which is why the two container rules at the bottom exist:
   dropped into a grid, the message would otherwise claim a column of its own
   instead of sitting under the field it belongs to. */
.sb-steps{display:flex;gap:10px;list-style:none;margin:0 0 28px;padding:0}
.sb-steps li{flex:1;text-align:center;font:var(--text-caption);color:var(--text-muted)}
.sb-steps li::after{
  content:"";display:block;height:4px;margin-top:9px;
  border-radius:var(--radius-pill);background:var(--gray-300);
}
.sb-steps li.is-on{font:var(--text-subtitle);font-weight:600;color:var(--green-800)}
.sb-steps li.is-on::after{background:var(--green-500)}

.sb-checkout__edit{display:flex;justify-content:flex-end;margin-top:14px}
/* Sits under the summary card's Change button; 20px read as if the two
   belonged together, so the required-field note gets its own air. */
/* `p.` qualified: brand-home.css sets `.sb-home p{margin:0}` at (0,1,1), which
   beats a bare class — the margin silently did nothing. */
.sb-page p.sb-checkout__req{
  font:var(--text-caption);color:var(--text-muted);text-align:right;margin:34px 0 14px;
}
.sb-checkout__row{margin-top:16px}
.sb-checkout__sub{margin-top:8px}
.sb-page p.sb-checkout__hint{
  font:var(--text-caption);color:var(--text-muted);
  text-align:center;margin-top:20px;
}

/* Card-processing fee, revealed under the summary while "pay by card" is the
   selected method. Same .sb-kv rows, tinted so the payable total reads as an
   addendum to the price above rather than a competing one. */
.sb-kv--fee{margin-top:10px;background:var(--blue-100)}
.sb-kv--fee .sb-kv__amount{color:var(--blue-800)}

/* Footnote for the "#" marker on a billed-later option. `p.` qualified for the
   same reason as __req above. */
.sb-page p.sb-checkout__foot{
  font:var(--text-caption);color:var(--text-muted);margin-top:10px;
}

/* The "we still need these details from you" list inside section 5. The legacy
   page shipped a <style> block resetting ul.normalUL because the theme killed
   list markers globally; the brand layers never did, so this only needs the
   indent back. */
.sb-checkout__needs{
  list-style:disc;padding-left:22px;margin:4px 0 18px;
  font:var(--text-body);color:var(--text-body-color);
}
.sb-checkout__needs li{margin-bottom:4px}

/* "What happens next" — reassurance directly below the commit button. */
.sb-checkout__next{
  background:var(--surface-card);border-radius:var(--radius-lg);
  box-shadow:var(--shadow-card);padding:22px;margin-top:26px;
}
.sb-checkout__next h2{font:var(--text-h4);margin-bottom:14px}
.sb-checkout__step{display:flex;align-items:flex-start;gap:10px;margin-bottom:10px}
.sb-checkout__stepn{
  flex:none;width:22px;height:22px;border-radius:50%;
  background:var(--action-primary);color:var(--text-inverse);
  font:700 12px/22px var(--font-display);text-align:center;
}
.sb-home a.sb-checkout__wa{
  display:inline-flex;align-items:center;gap:8px;margin-top:6px;
  padding-top:12px;border-top:1px solid var(--border-subtle);width:100%;
  font:var(--text-subtitle);font-weight:600;color:var(--green-600);
}

/* Checkout actions: Cancel left, Submit right — the DOM order matches, so the
   tab order does too. Both are sized as thumb targets rather than inheriting
   the compact default .sb-btn padding.

   Radius is inherited from .sb-btn (--radius-md) — no override needed now
   that .sb-btn--primary no longer forces a pill.

   justify-content is set explicitly: .sb-btn is an inline-flex that does not
   centre, so once the committing button gained a min-width its label sat
   against the left edge. */
.sb-form__foot--split{justify-content:space-between;gap:16px;margin-top:30px}
.sb-form__foot--split .sb-btn{
  min-height:52px;padding:14px 32px;font-size:16px;
  justify-content:center;
}
.sb-form__foot--split .sb-btn--quiet{
  background:var(--surface-card);
  border:1px solid var(--gray-300);
  color:var(--text-body-color);
}
.sb-form__foot--split .sb-btn--quiet:hover{
  background:var(--gray-100);border-color:var(--gray-500);color:var(--text-heading);
}
/* the committing action carries a little lift, tinted to whichever variant
   it is — coral for a true CTA, green when a page uses the plain primary */
.sb-form__foot--split .sb-btn--primary,
.sb-form__foot--split .sb-btn--cta{min-width:180px}
.sb-form__foot--split .sb-btn--primary{box-shadow:0 2px 10px rgba(108,194,67,.32)}
.sb-form__foot--split .sb-btn--primary:hover{box-shadow:0 4px 14px rgba(108,194,67,.42)}
.sb-form__foot--split .sb-btn--cta{box-shadow:0 2px 10px rgba(255,106,61,.32)}
.sb-form__foot--split .sb-btn--cta:hover{box-shadow:0 4px 14px rgba(255,106,61,.42)}
@media (max-width:767px){
  /* share the row equally instead of hugging their text */
  .sb-form__foot--split{gap:12px}
  .sb-form__foot--split .sb-btn{flex:1;padding:14px 12px}
}
.sb-req{color:var(--coral-600)}
.sb-strike{color:var(--text-muted);text-decoration:line-through}

.sb-formsec > h2 .sb-formsec__n{
  display:inline-flex;align-items:center;justify-content:center;
  width:26px;height:26px;margin-right:10px;border-radius:50%;
  background:var(--green-100);color:var(--green-800);
  font:var(--text-subtitle);font-weight:600;vertical-align:2px;
}

/* dismiss control on a page-level alert (replaces bootstrap's .btn-close) */
.sb-alert__x{
  margin-left:auto;flex:none;padding:2px;border:0;background:transparent;
  color:inherit;cursor:pointer;border-radius:var(--radius-sm);
}
.sb-alert__x .sb-icon{width:16px;height:16px}

/* ---- invalid field state ------------------------------------------------
   TWO validation builds are in play and they do not agree on class names:

   * stock jQuery Validate      -> errorClass "error",   errorElement <label>
   * the sky-forms 1.11.0 build -> errorClass "invalid", errorElement <em>,
     and it ALSO stamps `state-error` on the field's parent
     (assets2/plugins/sky-forms/version-2.0.1/js/jquery.validate.min.js)

   The booking pages load the sky-forms build, so styling only `.error` hit
   nothing at all and invalid fields kept the plain grey/blue treatment. Both
   conventions are covered here, plus `.sb-field.is-invalid` for the vanilla
   path in brandHelpBox.jsp.

   Blue is the FOCUS colour, and validate focuses the first invalid field on
   submit — so the error state has to win on :focus too, or the field reads as
   "active" rather than "wrong". The light red fill makes an unfocused invalid
   field obvious without relying on a 1px border. */
.sb-page em.invalid,
.sb-page label.error{
  display:block;margin-top:6px;font:var(--text-caption);font-style:normal;
  color:var(--coral-600);
}

.sb-page input.invalid:not([type="radio"]):not([type="checkbox"]),
.sb-page select.invalid,
.sb-page textarea.invalid,
.sb-page .state-error input:not([type="radio"]):not([type="checkbox"]),
.sb-page .state-error select,
.sb-page .state-error textarea,
.sb-page input.error:not([type="radio"]):not([type="checkbox"]),
.sb-page select.error,
.sb-page textarea.error,
.sb-field.is-invalid input:not([type="radio"]):not([type="checkbox"]),
.sb-field.is-invalid select,
.sb-field.is-invalid textarea{
  border-color:var(--coral-500);
  background:var(--coral-100);
}
.sb-page input.invalid:focus,
.sb-page select.invalid:focus,
.sb-page textarea.invalid:focus,
.sb-page .state-error input:focus,
.sb-page .state-error select:focus,
.sb-page .state-error textarea:focus,
.sb-page input.error:focus,
.sb-page select.error:focus,
.sb-page textarea.error:focus,
.sb-field.is-invalid input:focus,
.sb-field.is-invalid select:focus,
.sb-field.is-invalid textarea:focus{
  border-color:var(--coral-600);
  box-shadow:0 0 0 3px var(--coral-300);
}
/* A radio or checkbox has no usable border or fill, so ring it instead. This
   is what marks the unanswered "How to pay" and "I agree" groups. */
.sb-page input[type="radio"].invalid,
.sb-page input[type="checkbox"].invalid,
.sb-page input[type="radio"].error,
.sb-page input[type="checkbox"].error{
  outline:2px solid var(--coral-500);outline-offset:2px;
  accent-color:var(--coral-500);
}
/* the plugin also stamps a success state; keep it neutral rather than
   painting every completed field green */
.sb-page .state-success input,
.sb-page .state-success select,
.sb-page .state-success textarea{background:var(--surface-page)}

.sb-form__grid > em.invalid,
.sb-checks > em.invalid,
.sb-form__grid > label.error,
.sb-checks > label.error{grid-column:1 / -1;margin-top:0}

/* ---- responsive --------------------------------------------------------- */
@media (max-width:1100px){
  .sb-quotes{grid-template-columns:repeat(2,1fr)}
}
@media (max-width:900px){
  .sb-withaside{grid-template-columns:1fr;gap:28px}
  .sb-aside{position:static}
  .sb-feat__grid,.sb-feat__grid--2{grid-template-columns:1fr}
  .sb-duo,.sb-duo--flip{grid-template-columns:1fr;gap:24px}
  .sb-duo--flip > :first-child{order:0}
  .sb-form__grid{grid-template-columns:1fr}
}
@media (max-width:767px){
  .sb-pagehero{padding:32px var(--gutter) 36px}
  .sb-pagehero::before{                 /* horizontal fade leaves no photo this narrow */
    background:linear-gradient(180deg,
      rgba(255,255,255,.95) 0%,
      rgba(255,255,255,.84) 45%,
      rgba(255,255,255,.4) 100%);
  }
  .sb-content{padding:32px var(--gutter)}
  .sb-linklist--cols{grid-template-columns:1fr}
  .sb-quotes{grid-template-columns:1fr}
  .sb-form{padding:20px}
  .sb-authcard__boki{height:130px;top:-72px;right:14px}
  .sb-checks{grid-template-columns:1fr}
  .sb-choicerow{display:block}
  .sb-choices{margin-top:8px}
  .sb-kv{padding:8px 18px}
  .sb-kv__row{display:block}
  .sb-kv dd{text-align:left;margin-top:2px}
  .sb-error__code{font-size:72px}
}
