/*
  Smith & Wollensky — Vietnam theme stylesheet

  Typography, colour and layout geometry are taken verbatim from the live
  Smith & Wollensky compiled stylesheet (see mockups/_source/style.min.css).

  Fonts: English uses the four brand faces (griffon, gill-sans-nova,
  schoolbook, schoolbook-condensed) from the Adobe Fonts kit shared with the
  other S&W markets (assets/css/fonts.css). The brand files have no Vietnamese
  glyphs, so :lang(vi) swaps the --font-* tokens for self-hosted fonts with
  full Vietnamese support (assets/css/fonts-vi.css, enqueued only on
  Vietnamese pages, see inc/enqueue.php).
  Always set font-family through the tokens so the swap reaches every rule.

  The live type utility class names (.f__*) and colour utility class names
  (.u__c-*) are preserved so the markup stays directly comparable to
  mockups/_source/*.html.
*/

:root {
  /* ---- Brand colour tokens (live values) ---- */
  --color-gold: #976f41;
  --color-gold-light: #bc9b67;
  --color-green: #005b28;
  --color-green-deep: #013d1b;
  --color-cream: #feead8;
  --color-cream-soft: #fff7ef;
  --color-ink: #212529;
  --color-muted: #666263;
  --color-brown: #522a31;
  --color-wine: #522a31;
  --color-white: #ffffff;
  --color-black: #2d1a10;

  /* ---- Type stacks (live values) ---- */
  --font-display: griffon, Copperplate, serif;
  --font-sans: gill-sans-nova, "Gill Sans", "Segoe UI", -apple-system, sans-serif;
  --font-body: schoolbook, Georgia, serif;
  --font-section: schoolbook-condensed, Georgia, serif;
  --font-section-stretch: normal;

  /* ---- Spacing scale (4pt) ---- */
  --space-2xs: 0.25rem;
  --space-xs: 0.5rem;
  --space-sm: 0.75rem;
  --space-md: 1rem;
  --space-lg: 1.5rem;
  --space-xl: 2.5rem;
  --space-2xl: 4rem;
  --space-3xl: 6rem;
  --space-4xl: 8.5rem;

  /* ---- Motion ---- */
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
  --dur-fast: 160ms;
  --dur-med: 250ms;
  --dur-slow: 900ms;

  --radius-sm: 2px;
  --rule-hairline: 1px solid rgba(151, 111, 65, 0.25);

  /* Fixed-header offset — matches live `body { padding-top: 137px }` */
  --header-offset: 137px;

  /* One spacing value shared by both header nav columns, so every gap between
     nav items is identical regardless of how many items a column holds. The
     live site relies on space-around/space-between instead, which only looks
     even because it carries three items per column; the language switcher
     makes four on the right and that collapsed the gaps to 12px. A flat 40px
     applies throughout, since the desktop nav now only renders above 1400px
     where it fits. */
  /* Gap between header items. */
  --nav-gap: 24px;
  /* Desktop header scale: the nav text size. RESERVATIONS and the language
     switcher are sized from it, so changing this one value resizes all three
     together (16px: .header_link on the JP site, which this nav mirrors). */
  --nav-size: 16px;

  color-scheme: light;
}

/* Vietnamese: the brand files lack Vietnamese glyphs (U+1EA0–1EF9), so each
   token maps to the approved Vietnamese package (sources/fonts/README.txt),
   self-hosted in assets/css/fonts-vi.css. Griffon stays only in the
   "Smith & Wollensky" wordmark, which is an image. Sizes, weights and
   spacing stay on the brand values. */
:lang(vi) {
  --font-display: "Old Standard TT", Georgia, serif;
  --font-sans: Lato, "Segoe UI", -apple-system, sans-serif;
  --font-body: "Old Standard TT", Georgia, serif;
  --font-section: "Old Standard TT", Georgia, serif;
  --font-section-stretch: normal;
  /* Griffon is caps-only, so English posters render as capitals despite
     the lowercase transform. Old Standard TT has true lowercase. */
  --font-display-transform: uppercase;
}

/* Brand ampersand in running text: <span class="amp">&amp;</span>. */
span.amp {
  font-family: Baskerville, "Goudy Old Style", Palatino, "Book Antiqua", serif;
  font-style: italic;
}

/* ---------------------------------------------------------------- */
/* Reset                                                             */
/* ---------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }

html {
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}

body {
  margin: 0;
  max-width: 100vw;
  overflow-x: hidden;
  /* Live site: white page background. Cream is an accent, never the ground. */
  background-color: var(--color-white);
  color: var(--color-ink);
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 180%;
  padding-top: var(--header-offset);
  -webkit-font-smoothing: antialiased;
}

img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }
ul { margin: 0; padding: 0; list-style: none; }
button { font-family: inherit; }

h1, h2, h3, h4 {
  margin: 0;
  font-style: normal;
  font-weight: 700;
  overflow-wrap: anywhere;
}

/* Live wrapper width. The live site puts the 48px gutter on .header/.footer
   themselves and runs modules edge-to-edge inside a 1344px wrap; here the
   gutter lives on the wrap so every page section shares one measure. */
.u__wrap,
.wrap {
  width: 100%;
  max-width: 1344px;
  margin-left: auto;
  margin-right: auto;
  position: relative;
  padding-inline: 48px;
}
@media only screen and (max-width: 1200px) {
  .u__wrap,
  .wrap { padding-inline: 24px; }
}

.u__img-cover { position: relative; }
.u__img-cover img { width: 100%; height: 100%; object-fit: cover; }
.u__img-contain { position: relative; }
.u__img-contain img { width: 100%; height: 100%; object-fit: contain; }

/* Visually hidden but announced by screen readers — used to state that a
   card link opens a PDF or a new tab. */
.u__visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* Skip link */
.skip-link {
  position: absolute;
  left: -999px;
  top: 0;
  background: var(--color-green);
  color: var(--color-white);
  padding: var(--space-sm) var(--space-md);
  z-index: 2000;
  font-family: var(--font-sans);
}
.skip-link:focus {
  left: var(--space-md);
  top: var(--space-md);
}

:focus-visible {
  outline: 2px solid var(--color-gold);
  outline-offset: 3px;
}

/* ---------------------------------------------------------------- */
/* Typography utilities — verbatim from the live stylesheet           */
/* ---------------------------------------------------------------- */
.f__link-sans {
  font-family: var(--font-sans);
  font-style: normal;
  font-weight: 500;
  font-size: 14px;
  line-height: 20px;
  letter-spacing: .2em;
  text-transform: uppercase;
}

.f__section-header {
  font-family: var(--font-sans);
  font-style: normal;
  font-weight: 700;
  font-size: 21px;
  line-height: 32px;
  letter-spacing: .1em;
  text-transform: uppercase;
}

.f__poster {
  font-family: var(--font-display);
  font-style: normal;
  font-weight: 700;
  font-size: 54px;
  line-height: 140%;
  text-transform: var(--font-display-transform, lowercase);
}

.f__headline-h2 {
  font-family: var(--font-section);
  font-stretch: var(--font-section-stretch);
  font-style: normal;
  font-weight: 700;
  font-size: 32px;
  line-height: 120%;
  letter-spacing: .05em;
  text-transform: uppercase;
}

.f__headline-h3 {
  font-family: var(--font-section);
  font-stretch: var(--font-section-stretch);
  font-style: normal;
  font-weight: 700;
  font-size: 24px;
  line-height: 120%;
  letter-spacing: .05em;
  text-transform: uppercase;
}

.f__paragraph-medium {
  font-family: var(--font-body);
  font-style: normal;
  font-weight: 400;
  font-size: 19px;
  line-height: 180%;
}

.f__paragraph-regular {
  font-family: var(--font-body);
  font-style: normal;
  font-weight: 400;
  font-size: 16px;
  line-height: 180%;
}

/* Responsive step-downs (live breakpoints: 1200px, then 576px) */
@media only screen and (max-width: 1200px) {
  .f__poster { font-size: 36px; }
}
@media only screen and (max-width: 576px) {
  .f__poster { font-size: 28px; }
  .f__section-header { font-size: 16px; line-height: 20px; }
  .f__paragraph-regular { font-size: 15px; }
  .f__headline-h2 { font-size: 24px; }
}

/* ---------------------------------------------------------------- */
/* Colour utilities — verbatim from the live stylesheet               */
/* ---------------------------------------------------------------- */
.u__c-gold  { color: #976f41; }
.u__c-green { color: #005b28; }
.u__c-brown { color: #522a31; }
.u__c-white { color: #fff; }
.u__c-cream { color: #feead8; }
.u__c-grey  { color: #666263; }

/* ---------------------------------------------------------------- */
/* Placeholder / TBD styling                                        */
/* ---------------------------------------------------------------- */
.tbd {
  font-style: italic;
  color: var(--color-brown);
  border-bottom: 1px dashed var(--color-brown);
  padding-bottom: 1px;
}
/* On the dark green footer the wine tone is illegible — placeholders read
   as a dimmed white there instead. */
.site-footer .tbd,
.footer .tbd {
  color: rgba(255, 255, 255, 0.85);
  border-bottom-color: rgba(255, 255, 255, 0.5);
}

/* ---------------------------------------------------------------- */
/* Buttons (live `.button` treatment: gold outline, gold fill wipe)   */
/* ---------------------------------------------------------------- */
.button,
.btn {
  display: inline-block;
  position: relative;
  z-index: 2;
  font-size: 0;
  padding: 0;
  border: 0;
  background-color: transparent;
  cursor: pointer;
}
.button > span,
.btn > span {
  pointer-events: none;
  padding: 16px;
  border: 1px solid var(--color-gold);
  background: transparent;
  overflow: hidden;
  position: relative;
  display: inline-block;
  font-family: var(--font-sans);
  font-style: normal;
  font-weight: 500;
  font-size: 14px;
  line-height: 23px;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--color-gold);
  transition: color .25s ease;
}
.button > span::after,
.btn > span::after {
  content: "";
  width: 100%;
  height: 100%;
  display: block;
  background-color: var(--color-gold);
  position: absolute;
  top: 0;
  left: 0;
  z-index: -1;
  transform: translateY(100%);
  transition: transform .25s ease;
}
.button:hover > span,
.button:focus-visible > span,
.btn:hover > span,
.btn:focus-visible > span { color: var(--color-white); }
.button:hover > span::after,
.button:focus-visible > span::after,
.btn:hover > span::after,
.btn:focus-visible > span::after { transform: translateY(0); }

/* The gold wipe-up fill is the button's identity on the live site. Under
   reduced motion it is shortened rather than removed — `transition: none`
   turned it into an instant colour flip that read as "no hover effect". */
@media (prefers-reduced-motion: reduce) {
  .button > span, .button > span::after,
  .btn > span, .btn > span::after { transition-duration: 120ms; }
}

/* ---------------------------------------------------------------- */
/* Header — live geometry                                             */
/* ---------------------------------------------------------------- */
.header,
.site-header {
  /* Live padding is 40px top; the social row above the nav now occupies part
     of that space, so the top is trimmed to 24px to keep the wordmark at the
     same height it sits at on the live site. */
  padding: 24px 48px 40px;
  z-index: 20;
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  transition: transform .25s ease;
  background-color: #fff;
}
.header.hidden,
.site-header.hidden { transform: translateY(-100%); }

/* The header slide is essential motion, not decoration: it matches the live
   site's `transition: transform .25s ease` and is deliberately kept under
   prefers-reduced-motion. Windows "Show animations: off" reports reduce, and
   zeroing this made the header snap instead of glide. */

.header .u__wrap,
.site-header .u__wrap { padding-inline: 0; }

/* 12-column grid, vertically centred — mirrors the live Bootstrap row */
.header__row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
}
.header__col {
  min-width: 0;
}
.header__col--mobile-logo { flex: 0 0 25%; display: flex; text-align: left; }

/* Nav spacing.

   The live site uses space-around on the left column and space-between on the
   right, which happens to look even there because each column holds three
   items of similar width. Adding the language switcher makes four items in the
   right column, and space-between hands the leftover width to the outer edges
   — measured 12px between NEWS / CONTACT US / RESERVATIONS against 71px on the
   left. So the distribution is replaced with one explicit gap shared by both
   columns: spacing no longer depends on how many items a column holds, and the
   centre column still owns its third of the row, keeping the logo centred. */
/* Each side column takes exactly the width its own items need (flex-basis
   auto), and the centre column absorbs all remaining space. Equal thirds — or
   an equal flex-basis — split the surplus evenly, which the right column
   cannot use: it carries four items (~450px with the language switcher)
   against the left's three (~283px), so its content ran past its share and
   under the 288px logo below ~1300px. Sizing to content removes that overrun,
   and centring the logo inside the elastic middle column keeps it on the
   viewport's centre line at every width. */
/* Both side columns take an equal half of the row minus the logo's reserved
   width, and centre their own items within it. Pinning each group to the outer
   edge instead (flex-start / flex-end) leaves lopsided voids beside the
   wordmark — measured 234px to its left against 33px to its right, because the
   heavier group reaches much closer to the centre. Centring each group
   balances the whitespace while the shared column-gap keeps every gap between
   items identical. The left column now carries the four items (MENUS, PRIVATE
   EVENTS, NEWS, OUR STORY) and the right three (LOCATIONS, RESERVATIONS, the
   language switcher), the wordmark itself standing in for HOME. */
.header__col--left,
.header__col--right {
  flex: 1 1 0;
  min-width: 0;
  display: none;
  align-items: center;
  justify-content: center;
  column-gap: var(--nav-gap);
}

/* The middle column absorbs the leftover width, but the side columns are
   unequal (four items left, three right), so the column's own centre is not
   the viewport's. The logo is therefore taken out of flow and pinned to the
   header row's true centre line, which is what the design calls for; the
   column still reserves the horizontal space in flow, so neither nav group
   can encroach on the wordmark. */
.header__col--centre {
  flex: 1 1 auto;
  display: none;
  text-align: center;
}
/* The centre column never shrinks below the wordmark plus breathing room, so
   the two nav groups can never reach it. With both side columns on an equal
   flex basis, the logo's own column sits on the row's centre line and the
   wordmark is centred within it — no absolute positioning needed. */
/* At desktop the wrap becomes a three-track grid shared by the social row and
   the nav row (subgrid), so the social cell always spans exactly the nav's
   right column. Each side track splits the free space evenly (1fr) but never
   drops below its own content (max-content): the English nav fits, so the logo
   stays on the centre line, while the longer Vietnamese labels widen the left
   track instead of running under the wordmark. The Vietnamese menu carries
   three items left and two right (HÀNH TRÌNH moved across) so it also fits an
   equal share and the logo stays centred in both languages — measured 36px
   clear of the wordmark at 1400px. The centre track is the wordmark plus 32px
   of clear space either side. */
@media (min-width: 1400px) {
  .site-header .u__wrap {
    display: grid;
    /* Two equal side tracks that never grow to fit their content, so the
       wordmark sits on the same centre line in every language. The side
       columns absorb the difference instead: their items spread from the
       outer edge to the wordmark's 32px clear space (space-between). */
    grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  }
  /* Scoped to .site-header so these outrank the base .header__social-row
     flex rule further down the file. */
  .site-header .header__social-row,
  .site-header .header__row {
    grid-column: 1 / -1;
    display: grid;
    grid-template-columns: subgrid;
  }
  .header__col--centre { padding-inline: 48px; }
  /* Both menus start at a fixed point in every language: the left at the
     wrap's edge, the right at the wordmark's clear space. Longer labels only
     extend the right group further right. */
  /* The left group spreads its items across its whole track (space-between),
     so no blank band is left between the last link and the wordmark — the JP
     and PH sites read balanced the same way. The track is wider than the
     right one (3 items vs 4 plus the button and switcher), so the gaps on the
     left are wider than on the right; they stay equal to each other, which is
     what reads as balanced. */
  /* space-around, the value the PH site uses on its left column: the leftover
     width becomes a half-gap at each end and a full gap between items, so the
     last link keeps clear space from the wordmark instead of butting against
     it (space-between pinned NEWS to the centre column's edge). */
  .header__col--left { justify-content: space-around; }
  .header__col--right { justify-content: flex-start; }
  /* The icons ride on the right group, ending over the language switcher. */
  .header__right-group .header__social {
    position: absolute;
    right: 0;
    bottom: 100%;
    margin: 0 0 16px;
  }
  /* The group spans the nav row's full height, so the icons sit 16px above
     the row exactly as they did in their own row. */
  .header__col--right,
  .header__right-group { align-self: stretch; }
  /* Keeps the band above the nav the icons used to fill: their list's line
     box measured 36.8px, and the header's 173.6px height depends on it. */
  .site-header .header__social-row { min-height: 36.8px; }
}

.header__link {
  font-size: var(--nav-size);
  line-height: 1.4375; /* 23px at 16px */
  letter-spacing: .1em;
  display: inline-block;
  /* "CONTACT US" and "OUR STORY" must never break across two lines — the
     columns shrink before the labels do. */
  white-space: nowrap;
  transition: all .25s ease;
  /* Flex item in .header__col--left / --right: centre on the row's cross axis
     so the links and the RESERVATIONS button share one centre line. */
  align-self: center;
}
.header__link:hover { color: #976f41; }
.header__link[aria-current] { text-decoration: underline; text-underline-offset: 5px; }

/* Live width, held at every desktop width. */
.header__logo { width: 288px; display: inline-block; z-index: 25; }
.header__right-group {
  position: relative;
  display: flex;
  align-items: center;
  column-gap: var(--nav-gap);
}
/* Below the desktop breakpoint the mobile menu carries the social links. */
@media only screen and (max-width: 1399.98px) {
  .header__right-group .header__social { display: none; }
}
.header__logo img { width: 100%; height: auto; }
.header__logo-mobile { width: 50px; display: inline-block; }
.header__logo-mobile-open { width: auto; height: 18px; display: inline-block; }
.header__logo-mobile-open img { width: auto; height: 100%; }

/* Live rule is `margin-right: 24px`, which clears the hamburger sitting to its
   right. The hamburger is hidden at desktop, so the margin only pushes the
   button out of line with the nav links — applied at mobile only. */
/* The .button wrapper is inline-block with font-size:0 and an inline-block
   span, so the span's own baseline lands on the header row's text baseline and
   drags the button below the NEWS / CONTACT US links. The row is flex, so make
   the button a flex item that centres its span instead of baseline-aligning it. */
.header__reservations {
  display: inline-flex;
  align-items: center;
  align-self: center;
}
@media (max-width: 1199.98px) {
  .header__reservations { margin-right: 24px; }
}
/* Desktop matches the Taiwan site: 16px of padding all round (a 57px box),
   the same 16px type as the nav links. Its tighter 8px/10px padding only
   applies on smaller screens, where the mobile rule below takes over. */
.header__reservations > span {
  padding: var(--nav-size);
  font-size: var(--nav-size);
  line-height: 1.4375;
}

/* nav-open/close SVGs each draw their own 48x48 circle: the default is a gold
   disc with a white glyph, the __hover variant inverts to a white disc with a
   gold glyph and gold ring. The crossfade performs the whole inversion, so the
   icons must fill the button edge-to-edge with no padding of their own and the
   button's own background must stay transparent — otherwise the CSS gold disc
   shows through and the hover state looks like nothing happened. */
.header__hamburger {
  display: inline-block;
  vertical-align: middle;
  border-radius: 50%;
  position: relative;
  width: 48px;
  height: 48px;
  padding: 0;
  background-color: transparent;
  border: 0;
  cursor: pointer;
  flex-shrink: 0;
}
.header__hamburger-icon {
  position: absolute;
  width: 100%;
  height: 100%;
  top: 0;
  left: 0;
  transition: opacity .25s ease;
  pointer-events: none;
}
.header__hamburger-icon-hover { opacity: 0; }
/* Icon swap is hover-only, matching the live site. It previously also fired on
   :focus-visible, which made a programmatically-focused button (the modal's
   close X) render in its hover state before the pointer ever touched it — so a
   real hover appeared to do nothing. Keyboard users still get the global
   :focus-visible outline ring defined further up. */
.header__hamburger:hover .header__hamburger-icon { opacity: 0; }
.header__hamburger:hover .header__hamburger-icon-hover { opacity: 1; }

/* Language switcher. Reuses the .header__hamburger gold circle and its
   icon-crossfade, exactly as smithandwollensky.com.tw does — the icon shows the
   language you switch TO, and the __hover variant inverts to a white disc with
   gold letters and a gold ring. Desktop only (the live TW markup is
   `d-none d-xl-block`); the mobile nav carries a text link instead. */
/* The switcher sits in the shared column gap like every other nav item, so it
   needs no margin of its own. */
.header__lang { display: none; }

/* ---------------------------------------------------------------- */
/* Social row — one line of icons pinned to the top-right corner,     */
/* directly above the nav row and the language switcher.              */
/* ---------------------------------------------------------------- */
/* The header's own 40px top padding already supplies the clearance above
   the icons, so the row adds only the gap beneath itself. It is trimmed to
   16px at desktop so the wordmark does not drop further down the viewport
   than it does on the live site. */
/* The icons must line up over the language switcher, which is the last item in
   a centre-justified column — so its right edge sits inboard of the wrap by an
   amount that changes with the nav's content width. A fixed inset cannot track
   that (measured 61px at 1920px but 51px at 1400px). Instead the row mirrors
   the header's own three-column structure: two spacer cells matching
   .header__col--left and --centre, then a right cell that repeats the real
   column's `flex: 1 1 0` basis and centre justification. The icons therefore
   land on the switcher's centre line at every width, with no magic numbers. */
.header__social-row {
  display: flex;
  align-items: center;
  margin-bottom: 16px;
}
/* Matches .header__col--left. */
.header__social-spacer {
  flex: 1 1 0;
  min-width: 0;
}
/* Sits in the centre grid track, which .header__col--centre sizes. */
.header__social-spacer--centre {
  flex: 0 0 auto;
}
/* Matches .header__col--right's flex basis, so the cell spans exactly the same
   horizontal band as the nav group beneath it (measured: both edges align to
   0.00px at every width from 1400px to 2560px).

   The nav column is centre-justified, so the switcher — its last item — stops
   short of the band's right edge by half the column's leftover space. The nav
   group's content measures 389.74px, so that offset is
   (band width - 389.74) / 2, which CSS can express directly against the band
   because the cell and the column always share a width. Pinning the icons to
   the band's end and pushing them back by that amount lands the last icon's
   right edge on the switcher's, at every width — no measured constant, and it
   still holds at 1400px where the column narrows from 512px to 492px. */
.header__social-cell {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  align-items: center;
  justify-content: flex-end;
}
.header__social {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 0;
  list-style: none;
  flex: 0 0 auto;
  /* Half the nav column's leftover space; see above. The percentage resolves
     against .header__social-cell, which always matches the nav column's width,
     so this tracks the 1400px narrowing without a media query. */
  /* The right nav group is pinned to the column's end at desktop (see
     .header__col--right below), so the icons simply end where it ends. */
  margin: 0;
}
/* The icons are a framed outline set — Facebook and Instagram are drawn as
   rounded squares, Zalo as a speech bubble — so each already
   carries its own frame. Wrapping them in the nav's gold disc would nest one
   frame inside another, so the link is a plain hit area instead and the mark
   stands on its own. The 28px box is kept as the row's rhythm and as a
   comfortable pointer target. */
.header__social-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  color: var(--color-gold);
  flex-shrink: 0;
  transition: color .25s ease, opacity .25s ease;
}
/* No disc to invert, so hover shifts the stroke to the darker brand gold —
   the same cue the nav links use. */
.header__social-link:hover,
.header__social-link:focus-visible {
  color: var(--color-brown);
}
/* Client-supplied icon set, traced from the source PNGs into single filled
   paths so each mark inherits the gold brand colour through currentColor and
   scales without blurring. The outline weight is part of the traced artwork,
   so there is no stroke-width to set, and all three marks are square inside
   the shared 48-unit viewBox, so one size covers the row. */
.header__social-icon {
  display: block;
  overflow: visible;
}

/* The desktop nav switches to the hamburger at 1400px rather than the live
   site's 1200px. Measured: the widest nav column carries four items at a flat
   40px gap, which needs a wider viewport than 1200px to clear the centred
   288px wordmark. Raising the breakpoint keeps every desktop width correct
   instead of letting the nav run under the logo, and avoids shrinking the gaps
   to compensate; the live site can sit at 1200px only because it carries fewer
   nav items overall. */
@media (min-width: 1400px) {
  /* Three times the nav text: 48px at 16px. */
  .header__lang {
    width: calc(var(--nav-size) * 3);
    height: calc(var(--nav-size) * 3);
  }
  .header__col--mobile-logo { display: none; }
  .header__col--left { display: flex; }
  .header__col--centre { display: block; }
  .header__col--right { display: flex; }
  .header__hamburger.open { display: none; }
  .header__lang { display: inline-block; }
}
@media only screen and (max-width: 1399.98px) {
  .header, .site-header { padding: 5px 24px; }
  /* No room for a second row once the header collapses to 58px tall; the
     mobile nav panel carries the social links instead. */
  .header__social-row { display: none; }
  /* Below the desktop breakpoint both nav columns are hidden outright, so only
     the RESERVATIONS button and the hamburger remain; the right column takes
     the row's full remaining width and pins them to the end. */
  .header__col--right { flex: 0 0 75%; display: flex; justify-content: flex-end; }
  /* LOCATIONS lives in the right column too; left visible it overflowed the
     column's start and sat on the monogram. The mobile menu already lists it. */
  .header__col--right .header__link { display: none; }
  .header__reservations > span { font-size: 12px; padding: 10px 12px; }
  body { padding-top: 58px; }
}

/* ---------------------------------------------------------------- */
/* Popup overlays — one shared base for the mobile nav and the        */
/* exclusive-offers modal, matching the live `.popup`                 */
/* ---------------------------------------------------------------- */
.popup {
  z-index: 30;
  width: 100vw;
  height: 100vh;
  overflow: auto;
  position: fixed;
  top: 0;
  left: 0;
  background-color: #feead8;
  pointer-events: none;
  opacity: 0;
  transition: opacity .25s ease;
  padding-left: 48px;
  padding-right: 48px;
  display: none;
}
.popup.active {
  pointer-events: all;
  opacity: 1;
  display: block;
}
@media (prefers-reduced-motion: reduce) {
  .popup { transition-duration: 0s; }
}
@media only screen and (max-width: 1200px) {
  .popup { padding-left: 24px; padding-right: 24px; }
}

.popup__header {
  position: relative;
  background-color: transparent;
  padding-left: 0;
  padding-right: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding-top: 24px;
  padding-bottom: 24px;
}
.popup .header__hamburger.close { display: inline-block; z-index: 25; }

.main-nav { padding-block: var(--space-2xl); }
.main-nav__links { padding-left: 0; text-align: center; }
.main-nav__link { margin-bottom: 24px; }
.main-nav__link a { transition: opacity .25s ease; display: inline-block; }
.main-nav__link a:hover { color: var(--color-gold); }
@media only screen and (max-width: 576px) {
  .main-nav__link a { font-size: 22px; line-height: 22px; }
}

/* The mobile nav's language link, set off from the page links by a hairline
   rule so it reads as a mode switch rather than a sixth destination. The live
   TW mobile nav lists it as a plain text link in the same style. */
.main-nav__links--lang {
  margin-top: var(--space-lg);
  padding-top: var(--space-lg);
  border-top: var(--rule-hairline);
}
.main-nav__links--lang .main-nav__link { margin-bottom: 0; }
.main-nav__links--lang a { color: var(--color-gold); }

.main-nav__social {
  display: flex;
  gap: 15px;
  justify-content: center;
  padding-bottom: 30px;
}
/* The nav panel carries the same outline set as the header row, and those
   marks are self-framed (rounded squares and speech bubbles), so the link is a
   plain 44px hit area rather than a gold disc — nesting a frame inside a circle
   reads as two competing frames. 44px keeps the comfortable touch target. */
.main-nav__social .social-link {
  display: inline-flex;
  width: 44px;
  height: 44px;
  align-items: center;
  justify-content: center;
  color: var(--color-gold);
  transition: color .25s ease;
}
/* No disc to invert, so the stroke shifts to the darker brand gold on hover,
   matching the header row. */
.main-nav__social .social-link:hover,
.main-nav__social .social-link:focus-visible {
  color: var(--color-brown);
}
/* Client-supplied icon set, traced from the source PNGs to single filled paths
   so the marks inherit the gold/white brand colour through currentColor and
   stay crisp at any size. The artwork already carries its own outline weight,
   so there is no stroke to set — fill-rule="evenodd" keeps the counters
   (the "f" bowl, the lens ring, the Zalo lettering) knocked out. */
.main-nav__social .social-link__icon {
  display: block;
  overflow: visible;
}

/* The footer runs the same traced set as the header. Each mark is drawn inside
   its own rounded-square frame, so the links carry no disc of their own —
   nesting a frame inside a circle read as two borders. All three are square in
   the 48-unit viewBox, so one size covers the row. */
.footer__social .social-link__icon { display: block; width: 22px; height: 22px; }

/* Exclusive-offers modal — the live `.popup.exclusive` panel geometry */
/* The dialog takes focus on open (tabindex="-1") so the modal is announced
   without any control looking pre-activated. It is a container, not a control,
   so it does not draw the global focus ring — the ring would frame the whole
   600px panel. Focus is still trapped inside and Tab reaches the close button. */
.popup[tabindex]:focus,
.popup[tabindex]:focus-visible { outline: none; }

.popup.exclusive {
  max-width: 600px;
  max-height: 90vh;
  height: auto;
  width: 100%;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  padding-bottom: 30px;
  z-index: 40;
}
/* Backdrop behind the exclusive panel, so clicking outside can close it. */
.popup-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(45, 26, 16, 0.55);
  z-index: 35;
  opacity: 0;
  pointer-events: none;
  transition: opacity .25s ease;
}
.popup-backdrop.active { opacity: 1; pointer-events: all; }
@media (prefers-reduced-motion: reduce) {
  .popup-backdrop { transition-duration: 0s; }
}

.cross-area { text-align: right; margin-top: 1.5rem; margin-bottom: 1rem; }
.custom-popup__title { margin-bottom: var(--space-lg); }
.custom-popup__content { margin: 0; }

.sw-fade {
  position: relative;
  width: 100%;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 12px;
}
.sw-fade .sw-fade__item {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity .9s ease-in-out;
  pointer-events: none;
}
.sw-fade .sw-fade__item.is-active { opacity: 1; pointer-events: auto; }
.sw-fade img { width: 100%; height: auto; display: block; }
@media (prefers-reduced-motion: reduce) {
  .sw-fade .sw-fade__item { transition-duration: 0s; }
}

/* ---------------------------------------------------------------- */
/* Hero                                                              */
/* ---------------------------------------------------------------- */
/* The hero is NOT full-bleed on the live site. Measured against
   smithandwollensky.com.ph: 1806px hero inside an 1887px viewport, inset 48px
   each side. The hero itself has no width limit — the inset comes from the
   live `main.ignite-modules` padding (48px, 24px on mobile), which matches the
   header's own 48px gutter so the hero lines up with the nav above it.
   Height is 100vh capped at 756px on every page, home and inner alike. */
main {
  padding-left: 48px;
  padding-right: 48px;
}
@media only screen and (max-width: 1200px) {
  main { padding-left: 24px; padding-right: 24px; }
}

.m__hero {
  position: relative;
  margin-bottom: 68px;
  height: 100vh;
  max-height: 756px;
  overflow: hidden;
}
/* Keep the homepage slideshow inside the desktop gutters and edge-to-edge
   in the mobile layout, including when rendered inside Elementor. */
@media only screen and (max-width: 1200px) {
  .home .m__hero {
    width: 100vw;
    max-width: none;
    margin-left: calc(50% - 50vw);
    margin-right: calc(50% - 50vw);
  }
}
/* No short-hero variant on the live site: story, menu, news, contact, about and
   privacy all measure the same 756px as home. Kept as a no-op so the class in
   the markup stays harmless. */

.m__hero__background { width: 100%; height: 100%; position: absolute; top: 0; left: 0; }
.m__hero__background-image { width: 100%; height: 100%; z-index: 1; position: absolute; top: 0; left: 0; }
.m__hero__background-image .hero__slide {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity var(--dur-slow) var(--ease-in-out);
}
.m__hero__background-image .hero__slide.is-active { opacity: 1; }
.m__hero__background-image img { width: 100%; height: 100%; object-fit: cover; }
@media (prefers-reduced-motion: reduce) {
  .m__hero__background-image .hero__slide { transition: opacity 150ms linear; }
}
.m__hero__video {
  position: absolute;
  inset: 0;
  z-index: 1;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity var(--dur-slow) var(--ease-in-out);
}
.m__hero__video.is-playing { opacity: 1; }
.m__hero__background-tint {
  width: 100%;
  height: 100%;
  position: absolute;
  top: 0;
  left: 0;
  z-index: 2;
  background-color: rgba(0, 0, 0, 0.4);
}

.m__hero__overlay {
  position: relative;
  z-index: 3;
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}
/* Live inner container is max-width:100%, so it fills u__wrap's 1344px and the
   72px titles ("America's Steakhouse", "OUR AMERICAN DREAM") stay on one line.
   A 900px cap here was forcing them to wrap onto two. */
.m__hero__overlay-inner { text-align: center; max-width: 100%; }
.m__hero__overlay-subtitle {
  display: block;
  letter-spacing: .25em;
  font-size: 20px;
  margin: 0 0 var(--space-md);
}
.m__hero__overlay-title {
  display: block;
  margin-bottom: 40px;
  font-size: 72px;
}
@media only screen and (max-width: 1200px) {
  .m__hero {
    min-height: 400px;
    height: calc(100vh - 105px);
    margin-bottom: 48px;
  }
  .m__hero__overlay-subtitle { font-size: 18px; }
  .m__hero__overlay-title { font-size: 36px; }
}

/* ---------------------------------------------------------------- */
/* Feature media (image + copy row) — live m__fmedia                 */
/* ---------------------------------------------------------------- */
.m__fmedia { margin-bottom: 100px; }
.m__fmedia__row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  margin-inline: -12px;
}
.m__fmedia__row--reverse { flex-direction: row-reverse; }
.m__fmedia__col { flex: 0 0 100%; padding-inline: 12px; min-width: 0; }
.m__fmedia__content { padding-left: 70px; padding-right: 70px; }
.m__fmedia__title { margin-bottom: 48px; }
/* Poster-style titles in this module sit in a ~470px column; at the poster's
   54px "A STEAKHOUSE AND A LIVE JAZZ BAND BAR" ran to five lines. 42px holds it
   to three (44px is the measured limit). Below 1201px the poster step-downs
   (36px, 28px) already fit.
   Old Standard TT (Vietnamese) runs wider and left "BAR" alone on a third
   line at 42px. 38px holds it to two lines: the longest first line,
   "A STEAKHOUSE AND A", measures 11.84em = 450px in the narrowest ~472px
   column. */
@media (min-width: 1201px) {
  .m__fmedia .m__promo__content-title { font-size: 42px; }
  :lang(vi) .m__fmedia .m__promo__content-title { font-size: 38px; }
}
.m__fmedia__divider {
  width: 90px;
  height: 1px;
  background-color: #976f41;
  margin-bottom: 50px;
}
.m__fmedia__copy { margin-bottom: 0; }
/* Openings timeline under the copy: place left, year right, gold rules. */
.m__fmedia__milestones {
  list-style: none;
  margin: 40px 0 0;
  padding: 0;
  border-top: 1px solid #976f41;
}
.m__fmedia__milestone {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: baseline;
  gap: 4px 24px;
  padding: 14px 0;
  border-bottom: 1px solid rgba(151, 111, 65, .35);
}
.m__fmedia__milestone-year { margin: 0; white-space: nowrap; }
.m__fmedia__content--center .m__fmedia__milestone { justify-content: center; }
.m__fmedia__col--top { align-self: flex-start; }
.m__fmedia__col--bottom { align-self: flex-end; }
.m__fmedia__content--center { text-align: center; }
.m__fmedia__content--center .m__fmedia__divider { margin-inline: auto; }
.m__fmedia__content--right { text-align: right; }
.m__fmedia__content--right .m__fmedia__divider { margin-left: auto; }
.m__fmedia__content--justify .m__fmedia__copy { text-align: justify; }
.m__fmedia__media { position: relative; }
.m__fmedia__media img { width: 100%; height: auto; display: block; }

@media (min-width: 1200.01px) {
  .m__fmedia__col { flex: 0 0 50%; }
  /* Live rule: the hairline sits on the side the copy column faces. */
  .m__fmedia__right .m__fmedia__row { border-left: 1px solid #976f41; }
  .m__fmedia__left .m__fmedia__row { border-right: 1px solid #976f41; }
}
@media only screen and (max-width: 1400px) {
  .m__fmedia__content { padding-left: 25px; padding-right: 25px; }
}
@media only screen and (max-width: 1200px) {
  .m__fmedia {
    padding-bottom: 48px;
    margin-bottom: 48px;
    border-bottom: 1px solid #976f41;
  }
  .m__fmedia__content { padding-left: 0; padding-right: 0; }
  .m__fmedia__title { margin-bottom: 24px; }
  .m__fmedia__divider { margin-bottom: 24px; }
  .m__fmedia__media { height: 342px; margin-bottom: 24px; }
  .m__fmedia__media img { height: 100%; object-fit: cover; }
}

/* Auto-rotating fade slider (home article column) */
.sw-slider {
  position: relative;
  width: 100%;
  margin: auto;
  overflow: hidden;
  background: #000;
  aspect-ratio: 3 / 2;
}
.sw-slider .sw-slide {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity 1s ease-in-out;
}
.sw-slider .sw-slide.is-active { opacity: 1; }
/* Live inline rule: contain, so each frame shows in full and is never cropped. */
.sw-slider .sw-slide img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
}
@media (prefers-reduced-motion: reduce) {
  .sw-slider .sw-slide { transition-duration: 0s; }
}

/* ---------------------------------------------------------------- */
/* Carousel slider section — live m__cslider (Swiper 8)              */
/* ---------------------------------------------------------------- */
.m__cslider { margin-bottom: 120px; }
/* Match the Philippines carousel's usable width; page gutters remain outside. */
.m__cslider > .u__wrap { padding-inline: 0; }
.m__cslider__title { margin-bottom: 50px; }
.m__cslider__swiper { position: static; overflow: hidden; }
.m__cslider__swiper-slide-content {
  margin-right: 44px;
  padding-right: 44px;
  border-right: 1px solid #976f41;
  height: 100%;
}
.m__cslider__swiper-slide-highlight { height: 470px; }
.m__cslider__swiper-slide-title {
  padding-top: 32px;
  margin-bottom: 24px;
  font-size: 20px;
  display: block;
}
.m__cslider__swiper-slide-divider {
  background-color: #976f41;
  height: 1px;
  width: 114px;
  max-width: 50%;
  margin-bottom: 24px;
}
.m__cslider__swiper-slide-copy { margin-bottom: 24px; margin-top: 0; }

/* The live site uses bare divs here; this repo requires keyboard access, so
   these are real <button>s — hence the appearance reset. */
.m__cslider__swiper-arrow {
  position: absolute;
  right: 3px;
  top: 45%;
  width: 80px;
  height: 80px;
  background-color: #976f41;
  border: 1px solid #976f41;
  border-radius: 50%;
  z-index: 5;
  padding: 26px 31px;
  cursor: pointer;
  transition: all .25s ease;
  display: flex;
  align-items: center;
  justify-content: center;
  -webkit-appearance: none;
  appearance: none;
}
.m__cslider__swiper-arrow:hover,
.m__cslider__swiper-arrow:focus-visible { transform: scale(1.05); }
.m__cslider__swiper-arrow.hidden { opacity: 0; pointer-events: none; }
.m__cslider__swiper-arrow img { width: 15px; height: auto; }
.m__cslider__swiper-prev { left: -45px; right: auto; }
.m__cslider__swiper-next { right: 3px; }
/* The live hover is `transform: scale(1.05)` with `transition: all .25s ease`.
   Under reduced motion the scale is kept (it is the hover affordance, not
   decoration) and only the duration is shortened — `transform: none` here
   removed the effect entirely. */
@media (prefers-reduced-motion: reduce) {
  .m__cslider__swiper-arrow { transition-duration: 120ms; }
}

@media only screen and (max-width: 1200px) {
  .m__cslider { margin-bottom: 48px; }
  .m__cslider__title { margin-bottom: 24px; }
  .m__cslider__swiper-slide-content { padding-right: 0; margin-right: 0; border-right: 0; }
  .m__cslider__swiper-slide-highlight { height: 342px; }
  .m__cslider__swiper-arrow {
    top: 32%;
    width: 40px;
    height: 40px;
    padding: 3px 10px;
    display: flex;
    align-items: center;
    justify-content: center;
  }
  .m__cslider__swiper-arrow img { width: 15px; }
  .m__cslider__swiper-prev { left: -20px; }
  .m__cslider__swiper-next { right: -20px; }
}

/* Fallback layout if the Swiper CDN script does not load — the slides
   still read as a legible responsive grid rather than a stack of images. */
.m__cslider__swiper:not(.swiper-initialized) .swiper-wrapper {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--space-lg);
}
@media only screen and (max-width: 1200px) {
  .m__cslider__swiper:not(.swiper-initialized) .swiper-wrapper {
    grid-template-columns: minmax(0, 1fr);
  }
  .m__cslider__swiper:not(.swiper-initialized) ~ .m__cslider__swiper-arrow { display: none; }
}

/* ---------------------------------------------------------------- */
/* Location slider — live m__pslider (Swiper 8)                      */
/* Used by the Home "S&W Regional Footprint" section. The live       */
/* module lays each slide out on Bootstrap's grid; this repo carries  */
/* no Bootstrap, so the row is a plain flex row with the same 50/50   */
/* split and the same reversed order (text left, image right).       */
/* ---------------------------------------------------------------- */
.m__pslider { margin-bottom: 150px; position: relative; }
/* One hairline for the whole section, drawn as a pseudo-element on the wrap
   rather than a border on each slide. Putting it on the slide (as the live
   module does) repeats it six times, and the neighbouring slides' copies are
   visible inside the viewport because the swiper track is far wider than the
   wrap. Positioned to land on the same vertical as .m__fmedia__row's
   border-left beside HOME. */
.m__pslider .u__wrap { position: relative; }
.m__pslider .u__wrap::before {
  content: "";
  position: absolute;
  left: 36px;   /* wrap padding 48px - 12px row gutter, as .m__fmedia__row */
  width: 1px;
  /* Spans the slide area only, so it starts below the tab strip rather than
     alongside the section title. The tabs are a fixed block (title 50px
     margin + tab row + 45px margin), so the offset is a constant. */
  top: 166px;
  bottom: 0;
  background-color: var(--color-gold);
  z-index: 1;
  pointer-events: none;
}
.m__pslider__title { margin-bottom: 50px; }
/* No `overflow: hidden` on the wrap. The live module clips here to contain
   its tab strip, but .m__pslider__nav-wrapper already scrolls itself, and the
   clip cut 45px off the prev arrow, which hangs into the page gutter exactly
   as .m__cslider's does. */

/* Tab strip -------------------------------------------------------- */
.m__pslider__nav-wrapper { max-width: 100%; position: relative; }
.m__pslider__nav {
  margin: 0 0 45px;
  padding-left: 0;
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
}
.m__pslider__nav > li { display: inline-block; }

/* The live tabs are bare <li>s; these are real buttons for keyboard
   access, hence the appearance reset back to plain text. */
.m__pslider__nav-item {
  display: inline-block;
  width: auto;
  margin-right: 25px;
  margin-bottom: 15px;
  padding: 0;
  border: 0;
  background: none;
  /* Not `color: inherit`: like `font: inherit` before it, that beat the
     u__c-brown class on the same element and rendered the unselected tabs in
     the body ink (#212529) where Taiwan renders them brown (#522a31). The
     .active rule below still overrides this to gold. */
  color: var(--color-brown);
  text-align: left;
  cursor: pointer;
  transition: all .25s ease;
  -webkit-appearance: none;
  appearance: none;
  /* Restate .f__link-sans rather than `font: inherit`. These tabs are
     <button>s for keyboard access, and `font: inherit` took the body serif,
     overriding the class on the same element: measured against the live
     Taiwan tabs, ours rendered schoolbook 16px/400 at 3.2px tracking where
     Taiwan renders gill-sans-nova 14px/500 at 2.8px. */
  font-family: var(--font-sans);
  font-style: normal;
  font-weight: 500;
  font-size: 14px;
  line-height: 20px;
  letter-spacing: .2em;
  text-transform: uppercase;
}
.m__pslider__nav-item.active {
  color: var(--color-gold);
  text-decoration: underline;
}
.m__pslider__nav-item:hover { text-decoration: underline; }
.m__pslider__nav-item:focus-visible {
  outline: 2px solid var(--color-gold);
  outline-offset: 3px;
  text-decoration: underline;
}

/* Slides ----------------------------------------------------------- */
/* Static, not relative: the arrows are positioned against .m__pslider (the
   section) exactly as .m__cslider's are, so both sections' controls land on
   the same vertical. When this was `relative` the offsets resolved against
   this wrapper inside u__wrap instead, putting every arrow 48px — one page
   gutter — inboard of the ones below. */
.m__pslider__swiper-wrapper { position: static; }
/* The track is clipped, not left visible. The photograph's 22.5% pull-back is
   a decorative bleed inside the active slide, but on wide viewports the same
   pull let the INACTIVE neighbour's image show in the page gutter (measured:
   reaching x=169 at 1920px, though not at 1440px where the gutter is small).
   Both axes must be clipped: `overflow-x: clip` with `overflow-y: visible` is
   not a valid pairing — the visible axis is coerced and no clipping happens,
   which is exactly what the measurement showed. Nothing needs to escape
   vertically, and the arrows are children of .m__pslider, outside this box,
   so they still hang into the gutter. */
.m__pslider__swiper { overflow: clip; }
.m__pslider .swiper-backface-hidden .swiper-slide { backface-visibility: visible; }

.m__pslider__swiper-slide {
  transition: opacity .25s ease;
  height: auto;
}

/* Text left, image right — the live module gets this from
   .flex-xl-row-reverse on a Bootstrap row. */
.m__pslider__swiper-slide-row {
  display: flex;
  align-items: flex-start;
  margin-inline: -12px;
}
/* The photograph is pulled 22.5% left of its own column (10% once its slide
   is active), so it reaches back past the 50% line into this column. The text
   sits above it on z-index, which means an overlap does not clip — it just
   prints the address over the picture. Capping the text at the width that
   stays clear of the active image is what actually prevents that; the column
   itself keeps the live module's flex basis so the layout rhythm is intact. */
.m__pslider__swiper-slide-left {
  /* Positioned so z-index applies: without it the right column (relative,
     z-index 1) and its pulled-back photo sat over the text and swallowed
     hover and clicks on the directions, phone and email links. */
  position: relative;
  z-index: 2;
  flex: 0 0 41.6667%;   /* live col-xxl-5 of 12 */
  max-width: 41.6667%;
  /* 12px cancels the row's negative inline margin, 70px matches
     .m__fmedia__content, and 1px stands in for the border-left that shifts
     .m__fmedia__row's content — the hairline here is a pseudo-element, which
     takes no layout space, so without it this heading sat 1px left of HOME. */
  padding-left: 83px;
  padding-right: 12px;
}
/* Active image starts at 50% - 10% of the right column (= 45% of the row),
   so the text stops just short of that, measured from the row rather than
   from its own column. */
.m__pslider__swiper-slide-title,
.m__pslider__swiper-slide-divider,
.m__pslider__swiper-slide-content { max-width: min(100%, 380px); }
.m__pslider__swiper-slide-right {
  z-index: 1;
  flex: 0 0 50%;
  max-width: 50%;
  padding-inline: 12px;
  padding-bottom: 75px;
  position: relative;
}

/* The slide content slides in from the right once its slide is active.
   Held at opacity 0 until then, matching the live staggered reveal. */
.m__pslider__swiper-slide-title {
  /* The live module pads this title 51px/57px, which gave it a 178px box
     against HOME's 75.6px and left far too much air above the rule. HOME's
     title is plain .f__poster with no padding at all — the divider's own 50px
     margin is the entire gap — so this matches that. Font size stays at the
     module's 50px rather than .f__poster's 54px, because 54px pushes
     "HO CHI MINH CITY" back over the photograph. */
  padding-top: 0;
  padding-bottom: 0;
  font-size: 50px;
  display: block;
  /* The live module sets `overflow-wrap: normal` because its longest title is
     "TAICHUNG". "HO CHI MINH CITY" is far longer and overflowed the column
     into the photograph, so the title wraps between words here. It is a
     multi-word place name, so there is always a break point available and the
     mid-word breaking `anywhere` would allow is never needed. */
  overflow-wrap: break-word;
  margin: 0;
  opacity: 0;
  transform: translateX(50px);
  transition: opacity .5s ease, transform .5s ease;
  transition-delay: .1s;
}
/* 90px wide with 50px beneath it, matching .m__fmedia__divider rather than
   the live module's 114px/39px, so the rule under the location name reads the
   same as the one under HOME. */
.m__pslider__swiper-slide-divider {
  background-color: var(--color-gold);
  height: 1px;
  width: 90px;
  margin-bottom: 50px;
  opacity: 0;
  transform: translateX(50px);
  transition: opacity .5s ease, transform .5s ease;
  transition-delay: .1s;
}
.m__pslider__swiper-slide-content {
  margin-bottom: 35px;
  opacity: 0;
  transform: translateX(50px);
  transition: opacity .5s ease, transform .5s ease;
  transition-delay: .2s;
}
/* The Vietnam slides carry the same ADDRESS / PHONE / EMAIL rows as
   contact.html, so they reuse .m__map__content-row* wholesale rather than
   duplicating that styling here. Only the reveal and the row rhythm differ. */
.m__pslider__swiper-slide-content .m__map__content-row { margin-bottom: 24px; }
.m__pslider__swiper-slide-content .m__map__content-row:last-child { margin-bottom: 0; }
/* The email is a single unbreakable token (454px) wider than the live
   module's 80% text column (384px), so on the two Vietnam slides it ran out
   over the photograph. Breaking it mid-word reads badly, so the address
   block gets the full column width instead and the address keeps its 80%.
   The overseas slides carry no email and were never affected. */
/* The email is one unbreakable token wider than the 380px text cap. Breaking
   it mid-word reads badly, so it goes on its own line at a smaller size that
   fits whole. It sits below the phone number with only the photograph's blank
   lower half beside it, so the extra width costs nothing. */
.m__pslider__swiper-slide-mail {
  color: inherit;
  text-decoration: underline;
  display: inline-block;
  white-space: nowrap;
  font-size: 0.72em;
  letter-spacing: 0.01em;
}
.m__pslider__swiper-slide-mail:hover,
.m__pslider__swiper-slide-mail:focus-visible { color: var(--color-green); }

.m__pslider__swiper-slide-highlight {
  height: 617px;
  width: 112.5%;
  margin-left: -22.5%;
  transition: all .5s ease;
  transition-delay: .25s;
}

/* The cream card overlaps the bottom of the photograph. */
.m__pslider__swiper-slide-card {
  opacity: 0;
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  z-index: 1;
  margin: 0 auto;
  width: 480px;
  background-color: var(--color-cream);
  padding: 66px 80px 65px;
  transform: translateY(20px);
  transition: opacity .5s ease, transform .5s ease;
  transition-delay: .5s;
}
.m__pslider__swiper-slide-card-title { margin-bottom: 24px; }
.m__pslider__swiper-slide-card-divider {
  width: 90px;
  height: 1px;
  background-color: var(--color-gold);
  margin-bottom: 24px;
}
.m__pslider__swiper-slide-excerpt { margin-bottom: 24px; margin-top: 0; }

/* Active slide: everything settles into place and the photo widens. */
.m__pslider__swiper-slide.swiper-slide-active .m__pslider__swiper-slide-title,
.m__pslider__swiper-slide.swiper-slide-active .m__pslider__swiper-slide-divider,
.m__pslider__swiper-slide.swiper-slide-active .m__pslider__swiper-slide-content,
.m__pslider__swiper-slide.swiper-slide-active .m__pslider__swiper-slide-card {
  opacity: 1;
  transform: translateX(0);
}
.m__pslider__swiper-slide.swiper-slide-active .m__pslider__swiper-slide-card {
  transform: translateY(0);
}
.m__pslider__swiper-slide.swiper-slide-active .m__pslider__swiper-slide-highlight {
  width: 110%;
  margin-left: -10%;
}

/* Arrows. As with .m__cslider these are real <button>s, so the
   appearance is reset. */
.m__pslider__swiper-arrow {
  position: absolute;
  top: 45%;
  width: 80px;
  height: 80px;
  background-color: var(--color-gold);
  border: 1px solid var(--color-gold);
  border-radius: 50%;
  z-index: 5;
  padding: 26px 31px;
  cursor: pointer;
  transition: all .25s ease;
  display: flex;
  align-items: center;
  justify-content: center;
  -webkit-appearance: none;
  appearance: none;
}
.m__pslider__swiper-arrow:hover,
.m__pslider__swiper-arrow:focus-visible { transform: scale(1.05); }
.m__pslider__swiper-arrow.hidden { opacity: 0; pointer-events: none; }
.m__pslider__swiper-arrow img { width: 18px; height: auto; }
/* Same offsets as .m__cslider's arrows so both sections' controls sit on the
   identical vertical: -45px hangs the prev arrow into u__wrap's gutter and
   3px keeps the next arrow inside the wrap's right edge. The earlier -88px
   pushed the next arrow 43px past the wrap, where the viewport clipped it. */
.m__pslider__swiper-prev { left: -45px; right: auto; }
.m__pslider__swiper-next { right: 3px; left: auto; }

/* As with .m__cslider, the scale is the hover affordance rather than
   decoration, so reduced motion shortens the durations instead of
   removing the transforms — which would kill the reveal outright and
   leave every slide stuck at opacity 0. */
@media (prefers-reduced-motion: reduce) {
  .m__pslider__swiper-arrow,
  .m__pslider__swiper-slide-highlight,
  .m__pslider__swiper-slide-title,
  .m__pslider__swiper-slide-divider,
  .m__pslider__swiper-slide-content,
  .m__pslider__swiper-slide-card { transition-duration: 150ms; transition-delay: 0s; }
}

/* Narrower columns below 1400px: the left column's padding tracks
   .m__fmedia__content's own 1400px value, and the title scales down so the
   longest name still clears the photograph. */
@media only screen and (max-width: 1400px) {
  /* 12px gutter + 25px (.m__fmedia__content's own 1400px padding) + 1px for
     the border, so the heading stays on HOME's vertical here too. */
  .m__pslider__swiper-slide-left { padding-left: 38px; }
  /* At 50px the word "MINH" alone is wider than the text cap, so the longest
     title still reached the photograph. The type scales down with the column
     rather than the cap growing, which would put the text back over the
     image. */
  .m__pslider__swiper-slide-title { font-size: 42px; }
}

/* Below the live xl breakpoint the slide stacks: photo first at full
   width, then the card in normal flow, then the address block. */
@media only screen and (max-width: 1200px) {
  .m__pslider { margin-bottom: 48px; }
  .m__pslider__title { margin-bottom: 27px; }
  /* Below the desktop breakpoint the six tabs cannot fit, so the strip
     becomes a single horizontally scrollable row. Both `nowrap` and
     `flex-shrink: 0` are required: without the latter, a nowrap flex
     container still squeezes the items until their labels wrap, which
     produced a second row that horizontal scrolling could never reach.
     The live site forces this with a flat `min-width: 1500px`, which
     overshoots and leaves dead space at the end of the scroll; sizing
     to the content instead scrolls exactly as far as there are tabs. */
  .m__pslider__nav {
    margin-bottom: 27px;
    flex-wrap: nowrap;
    width: max-content;
    min-width: 100%;
  }
  .m__pslider__nav > li { flex: 0 0 auto; }
  .m__pslider__nav-item { white-space: nowrap; }
  .m__pslider__nav-wrapper {
    overflow-x: auto;
    overflow-y: hidden;
    -webkit-overflow-scrolling: touch;
    /* Fade the right edge so it reads as scrollable rather than cut off. */
    -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 24px), transparent 100%);
    mask-image: linear-gradient(to right, #000 calc(100% - 24px), transparent 100%);
  }
  /* Once scrolled to the end there is nothing more to hint at. */
  .m__pslider__nav-wrapper.is-scroll-end {
    -webkit-mask-image: none;
    mask-image: none;
  }
  .m__pslider__swiper-slide { margin-left: auto; border-left: 0; }
  .m__pslider__swiper-slide.swiper-slide-active { border: 0; }

  /* Stacked: no columns, so the row drops its negative gutter margin. Left in
     place, that -12px made every slide's content wider than its slide, which
     spilled past the track's clip and showed the next slide's photo as a
     strip down the right edge. */
  .m__pslider__swiper-slide-row {
    display: block;
    margin-inline: 0;
  }
  /* The section hairline goes too, exactly as .m__fmedia's border-left does
     below this breakpoint — there is no side-by-side column for it to edge. */
  .m__pslider .u__wrap::before { display: none; }
  .m__pslider__swiper-slide-left,
  .m__pslider__swiper-slide-right {
    flex: none;
    max-width: 100%;
    padding-left: 0;
  }
  .m__pslider__swiper-slide-right { padding-bottom: 0; }

  .m__pslider__swiper-slide-title { width: 100%; padding-top: 0; padding-bottom: 24px; font-size: 36px; }
  .m__pslider__swiper-slide-divider { margin-bottom: 24px; }
  .m__pslider__swiper-slide-content { max-width: 100%; margin-bottom: 24px; }
  .m__pslider__swiper-slide-highlight { height: 342px; width: 100%; margin-left: 0; margin-bottom: 24px; }
  .m__pslider__swiper-slide.swiper-slide-active .m__pslider__swiper-slide-highlight {
    width: 100%;
    margin-left: 0;
  }
  .m__pslider__swiper-slide-card {
    max-width: 100%;
    width: 100%;
    position: relative;
    margin: 0 auto 24px;
    padding: 24px 24px 28px;
  }
  /* `overflow: visible` on the swiper lets the desktop photo bleed past its
     column, but once the slides stack it also lets the NEXT slide's image
     show as a strip down the right edge. Clipping the track (not .u__wrap,
     which must stay visible for the arrows) hides it. */
  .m__pslider__swiper { overflow: hidden; }
  .m__pslider__swiper-arrow {
    top: 38%;
    width: 40px;
    height: 40px;
    padding: 3px 10px;
  }
  .m__pslider__swiper-arrow img { width: 15px; }
  .m__pslider__swiper-prev { left: -20px; }
  .m__pslider__swiper-next { right: -20px; }
}

/* Fallback if the Swiper CDN script does not load: show only the first
   slide (the tabs and arrows cannot work without Swiper) and drop the
   reveal offsets so the content is actually legible. */
.m__pslider__swiper:not(.swiper-initialized) .m__pslider__swiper-slide + .m__pslider__swiper-slide { display: none; }
.m__pslider__swiper:not(.swiper-initialized) .m__pslider__swiper-slide-title,
.m__pslider__swiper:not(.swiper-initialized) .m__pslider__swiper-slide-divider,
.m__pslider__swiper:not(.swiper-initialized) .m__pslider__swiper-slide-content,
.m__pslider__swiper:not(.swiper-initialized) .m__pslider__swiper-slide-card {
  opacity: 1;
  transform: none;
}
.m__pslider__swiper:not(.swiper-initialized) ~ .m__pslider__swiper-arrow,
.m__pslider__swiper:not(.swiper-initialized) .m__pslider__nav-wrapper { display: none; }

/* ---------------------------------------------------------------- */
/* Generic content sections                                          */
/* ---------------------------------------------------------------- */
.section { padding-block: var(--space-3xl); }
.section--tight { padding-block: var(--space-2xl); }
.section--cream-soft { background: var(--color-cream-soft); }
.section--green { background: var(--color-green); }
.section-heading { margin-bottom: var(--space-2xl); text-align: center; }
.section-lead { margin: 0 auto var(--space-xl); max-width: 620px; text-align: center; }

/* ---------------------------------------------------------------- */
/* Home business-lunch promo re-entry link                            */
/* ---------------------------------------------------------------- */
.promo-strip {
  display: grid;
  grid-template-columns: minmax(0, 200px) minmax(0, 1fr);
  gap: var(--space-xl);
  align-items: center;
  border: 1px solid rgba(151, 111, 65, 0.35);
  padding: var(--space-xl);
}
.promo-strip__media img { width: 100%; }
.promo-strip__title { margin-bottom: var(--space-sm); }
.promo-strip__copy { margin: 0 0 var(--space-lg); }
@media (max-width: 720px) {
  .promo-strip { grid-template-columns: minmax(0, 1fr); text-align: center; }
  .promo-strip__media { max-width: 200px; margin: 0 auto; }
}

/* ---------------------------------------------------------------- */
/* story-card-small — shared PDF/article card (menu + news pages)    */
/* Geometry and transitions are the live values from                  */
/* mockups/_source/style.min.css.                                     */
/* ---------------------------------------------------------------- */
.story-card-small-highlight {
  width: 100%;
  overflow: hidden;
  height: 285px;
  margin-bottom: 35px;
}
.story-card-small-highlight-wrapper {
  height: 100%;
  transition: transform .5s ease;
}
.story-card-small-title {
  transition: all .25s ease;
  padding-bottom: 20px;
  min-height: 133px;
  font-size: 20px;
}
.story-card-small a { display: block; }
.story-card-small a:hover { text-decoration: none; }
.story-card-small a:hover img { transform: scale(1.05); }
.story-card-small a:hover .story-card-small-title { color: var(--color-gold); }
.story-card-small img { transition: transform .25s ease; }
/* The link wraps image and title, so the ring must be visible around the
   whole card rather than only the text node. */
.story-card-small a:focus-visible {
  outline: 2px solid var(--color-gold);
  outline-offset: 4px;
}

/* The hover scale is the affordance that tells a reviewer the card is
   interactive, so reduced motion shortens the duration instead of
   removing the transform. */
@media (prefers-reduced-motion: reduce) {
  .story-card-small-highlight-wrapper,
  .story-card-small img { transition-duration: 120ms; }
  .story-card-small-title { transition-duration: 120ms; }
}

@media only screen and (max-width: 1200px) {
  .story-card-small-highlight { height: 324px; margin-bottom: 24px; }
  .story-card-small-title { min-height: 0; }
}

/* ---------------------------------------------------------------- */
/* Card grids — the live Bootstrap row-cols behaviour, hand-rolled   */
/* since this build ships no Bootstrap. xl is 1200px throughout.     */
/* ---------------------------------------------------------------- */
.card-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-xl);
  justify-content: center;
}
/* row-cols-md-2 */
@media only screen and (min-width: 768px) {
  .card-grid--4up { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
/* row-cols-lg-3 */
@media only screen and (min-width: 992px) {
  .card-grid--4up { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
/* row-cols-xl-4 */
@media only screen and (min-width: 1200px) {
  .card-grid--4up { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  /* col-12 col-xl-4 — news page is 1-up below xl, 3-up at xl. */
  .card-grid--3up { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
/* justify-content-center with a capped track width: short rows (the three
   main menus, the two Special Offer cards) centre rather than stretching
   across the full container. */
.card-grid--centred {
  justify-content: center;
  grid-auto-flow: row;
}
@media only screen and (min-width: 768px) {
  .card-grid--centred { grid-template-columns: repeat(2, minmax(0, min(100%, 320px))); }
}
/* 3-up at lg. Tracks are declared per row-length so a short row never
   leaves an empty trailing track off-centre: the Special Offer pair keeps
   the 2-track template, the three main menus get a third. */
@media only screen and (min-width: 992px) {
  .card-grid--centred--3 { grid-template-columns: repeat(3, minmax(0, min(100%, 320px))); }
}

/* ---------------------------------------------------------------- */
/* Menu page                                                         */
/* ---------------------------------------------------------------- */
.m__menus { padding-block: var(--space-3xl); }
.m__menus__title { text-align: center; margin-bottom: var(--space-2xl); }
.m__menus__title + .card-grid { margin-bottom: var(--space-3xl); }
.m__menus .card-grid:last-child { margin-bottom: 0; }
@media only screen and (max-width: 1200px) {
  .m__menus { padding-block: var(--space-2xl); }
  .m__menus__title { margin-bottom: var(--space-xl); }
  .m__menus__title + .card-grid { margin-bottom: var(--space-2xl); }
}

/* Menu content now lives entirely in the linked PDFs, matching the live
   site; the note below the grids explains that to reviewers. */
.menu-pdf-note {
  max-width: 720px;
  margin: var(--space-2xl) auto 0;
  text-align: center;
  color: var(--color-muted);
  font-size: 15px;
}

/* ---------------------------------------------------------------- */
/* News page                                                         */
/* ---------------------------------------------------------------- */
.m__pfeed { padding-block: var(--space-3xl); }
@media only screen and (max-width: 1200px) {
  .m__pfeed { padding-block: var(--space-2xl); }
}
/* The live site draws a 16:9 background-image div; a real <img> with the
   same ratio is used instead so the artwork is content, not decoration.
   The frame therefore takes its height from the ratio rather than the
   fixed 285px the menu cards use. */
.story-card-small-highlight--ratio {
  height: auto;
  aspect-ratio: 16 / 9;
  margin-bottom: var(--space-md);
}
.story-card-small-highlight--ratio .story-card-small-highlight-wrapper { height: 100%; }
@media only screen and (max-width: 1200px) {
  .story-card-small-highlight--ratio { height: auto; margin-bottom: var(--space-md); }
}
.news-card__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.news-card__meta { margin: 0 0 var(--space-xs); }

/* News pagination (theme stage: the mockup shows a single page). */
.news-pagination { margin-top: var(--space-2xl); }
.news-pagination .nav-links {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-xs);
}
.news-pagination .page-numbers {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
  padding: 0 var(--space-sm);
  font-family: var(--font-sans);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-gold);
  border: var(--rule-hairline);
  text-decoration: none;
  transition: color var(--dur-fast) ease, background-color var(--dur-fast) ease;
}
.news-pagination a.page-numbers:hover { background: var(--color-gold); color: var(--color-white); }
.news-pagination .page-numbers.current { background: var(--color-green); border-color: var(--color-green); color: var(--color-white); }
.news-pagination .page-numbers.dots { border-color: transparent; }
.news-pagination a:focus-visible { outline: 2px solid var(--color-gold); outline-offset: 2px; }

/* News article (single post written in the standard editor). */
.news-article { padding-block: var(--space-3xl); }
.news-article__inner { max-width: 760px; margin-inline: auto; }
.news-article__title { margin: 0 0 var(--space-xl); }
.news-article__content > * + * { margin-top: var(--space-md); }
.news-article__content h2,
.news-article__content h3 { font-family: var(--font-display); color: var(--color-green); margin-top: var(--space-xl); }
.news-article__content a { color: var(--color-gold); text-decoration: underline; text-underline-offset: 3px; }
.news-article__content img,
.news-article__content figure { max-width: 100%; height: auto; }
.news-article__content blockquote {
  margin-inline: 0;
  padding-left: var(--space-lg);
  border-left: 2px solid var(--color-gold);
  font-style: italic;
}
.news-article__back { margin-top: var(--space-2xl); padding-top: var(--space-lg); border-top: var(--rule-hairline); }
.news-article__back a { text-decoration: none; }
.news-article__back a:hover,
.news-article__back a:focus-visible { text-decoration: underline; }
@media only screen and (max-width: 1200px) {
  .news-article { padding-block: var(--space-2xl); }
}
@media (prefers-reduced-motion: reduce) {
  .news-pagination .page-numbers { transition: none; }
}

/* ---------------------------------------------------------------- */
/* Locations page — live m__map, m__llist and m__ltext modules       */
/* Geometry is taken verbatim from mockups/_source/tw-style.min.css  */
/* except where noted. The live page pairs each location with a      */
/* Google map; this build has no Maps API key and the Vietnam        */
/* addresses are unconfirmed, so that half carries a featured venue  */
/* image instead (explicit client request).                          */
/* ---------------------------------------------------------------- */

/* Full-bleed out of the wrap. The live rule is -49px/-24px, which cancels
   the live 48px/24px main.ignite-modules padding plus 1px of Bootstrap
   gutter rounding. This build has no Bootstrap gutters, so the negatives
   are exactly -48px/-24px to match main's own padding — -49px would leave
   a 1px sliver past the viewport edge and trip horizontal overflow. */
/* The live Taiwan page runs these rows full-bleed via negative side margins.
   Here they sit inside the page gutter instead, matching the Our Story
   (.m__fmedia) sections, so the image and the information panel both keep a
   margin from the viewport edges. */
.m__map {
  margin-bottom: 81px;
}
.m__map__row {
  display: flex;
  flex-wrap: wrap;
  align-items: stretch;
}
/* Image right / cream panel left on the second location, for rhythm.
   Follows the .m__fmedia__row--reverse approach already in this sheet. */
.m__map__row--reverse { flex-direction: row-reverse; }
/* Live rule is `.m__map .col-xl-6 { padding: 0 }` — the two halves butt
   together with no gutter. */
.m__map__col {
  flex: 0 0 100%;
  padding: 0;
  min-width: 0;
}

/* The live panel and map are both a fixed 850px. Measured in the browser, the
   Vietnam panel content (four info rows, three hours sub-headings and a
   directions block per location) needs 865px at every desktop width, so a
   fixed 850px would clip it — the live Taiwan copy is shorter and happens to
   fit. `min-height: 850px` plus `align-items: stretch` keeps the live
   proportion and the equal-height pairing, and lets the row grow instead of
   scrolling internally if the client's final copy runs longer still.
   The image half stretches to whatever the panel settles on. */
.m__map__media {
  width: 100%;
  min-height: 850px;
  overflow: hidden;
}
.m__map__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.m__map__content {
  background-color: #feead8;
  min-height: 850px;
  padding: 45px 60px;
}
.m__map__content-title { margin-bottom: 24px; }
.m__map__content-divider {
  height: 1px;
  width: 90px;
  background-color: #976f41;
  margin-bottom: 48px;
}
.m__map__content-row { margin-bottom: 20px; }
.m__map__content-row:last-child { margin-bottom: 0; }
.m__map__content-row-title { margin-bottom: 10px; }
.m__map__content-row-content p { margin: 0 0 var(--space-md); }
.m__map__content-row-content p:last-child { margin-bottom: 0; }
.m__map__content-row-content a {
  color: inherit;
  text-decoration: underline;
}
.m__map__content-row-content a:hover { color: #005b28; }

/* Boundary is 1201px, not the 1200.01px used elsewhere in this sheet: Chrome
   rounds a fractional min-width down, so `min-width: 1200.01px` and
   `max-width: 1200px` BOTH match at exactly 1200px. That overlap put a 342px
   mobile image frame beside a full-height desktop panel at 1200px. Integer
   bounds make the switch exclusive. */
@media (min-width: 1201px) {
  .m__map__col { flex: 0 0 50%; }
  /* Both halves fill whichever height the taller one settles on. Scoped to
     desktop: this child selector outranks the 342px mobile rule below, so
     leaving it unscoped let the image keep its intrinsic ratio on mobile. */
  .m__map__col > .m__map__media,
  .m__map__col > .m__map__content { height: 100%; }
}
@media only screen and (max-width: 1200px) {
  .m__map {
    margin-bottom: 48px;
  }
  /* Live mobile values: 342px map frame, auto-height panel. */
  .m__map__media { min-height: 0; height: 342px; }
  .m__map__content {
    min-height: 0;
    height: auto;
    padding: 27px 24px;
  }
  .m__map__content-divider { margin-bottom: 24px; }
  /* row-reverse would put the image below the panel once the row collapses
     to a single column, which reads as the wrong order. */
  .m__map__row--reverse { flex-direction: row; }
}

/* ---- Explore More Asia Locations — live m__llist ---- */
.m__llist { padding-bottom: var(--space-xl); }
/* The live site gives this line body-copy styling (f__paragraph-medium on a
   bare <p>), which reads as a stray label rather than the heading for three
   cards. It keeps the live class in the markup for comparability but is
   restyled here to the section-header treatment used elsewhere on the site. */
.m__llist__heading {
  margin-bottom: var(--space-xl);
  font-family: var(--font-sans);
  font-weight: 700;
  font-size: 21px;
  line-height: 32px;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--color-gold);
}
.m__llist__heading p { margin: 0; }
@media only screen and (max-width: 576px) {
  .m__llist__heading { font-size: 16px; line-height: 20px; }
}
.m__llist__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-xl);
}
/* col-12 col-xl-4 — 1-up below xl, 3-up at xl. This build's xl is 1200px, and
   the down-level rules on this page are `max-width: 1200px`, so the up-level
   bound is 1201px — see the note on .m__map__col above. A bare 1200px (or a
   fractional 1200.01px, which Chrome rounds down) makes both queries match at
   exactly 1200px and leaves this grid 3-across while the location rows have
   already stacked. */
@media only screen and (min-width: 1201px) {
  .m__llist__grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* Live height is 540px. The three source images are 960x540, 960x540 and
   933x700, so a 540px frame upscales two of them. 360px is the equal height
   used across all three cards instead — it holds a 16:9 crop at the ~400px
   column width these cards occupy inside the 1344px wrap. */
.m__llist__card-highlight {
  width: 100%;
  height: 360px;
  overflow: hidden;
  margin-bottom: 32px;
}
/* The scale target is the wrapper, not the img, so the 1.1 scale is clipped
   by the overflow:hidden frame above it. */
.m__llist__card-highlight-wrapper {
  width: 100%;
  height: 100%;
  transition: transform .5s ease;
}
.m__llist__card-highlight-wrapper img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.m__llist__card a { display: block; }
.m__llist__card-title {
  transition: color .25s ease;
  margin-bottom: 16px;
}
.m__llist__card-divider {
  height: 1px;
  width: 115px;
  background-color: #976f41;
  margin-bottom: 16px;
}
.m__llist__card-excerpt { margin-bottom: 16px; }
.m__llist__card-link { margin-bottom: 0; }
.m__llist__card a:hover { text-decoration: none; }
.m__llist__card a:hover .m__llist__card-title { color: #976f41; }
.m__llist__card a:hover .m__llist__card-highlight-wrapper { transform: scale(1.1); }
/* The link wraps image, title and excerpt, so the ring must surround the
   whole card rather than only the text node. */
.m__llist__card a:focus-visible {
  outline: 2px solid var(--color-gold);
  outline-offset: 4px;
}

/* The image scale and title colour shift are the affordance that tells a
   reviewer the card is interactive, so reduced motion shortens the
   durations rather than removing the transform. */
@media (prefers-reduced-motion: reduce) {
  .m__llist__card-highlight-wrapper { transition-duration: 150ms; }
  .m__llist__card-title { transition-duration: 120ms; }
}

@media only screen and (max-width: 1200px) {
  .m__llist__card-highlight { height: 342px; margin-bottom: 24px; }
}

/* ---- MENUS page: chef statement and the two-up location index ---- */
/* The reference menu page opens with a culinary-officer statement, then lists
   one card per venue. Both reuse modules already in this sheet rather than
   adding new ones: m__ltext for the statement, m__llist for the cards. */

/* m__ltext holds its copy to one line with nowrap for the contact-page
   sentence. A multi-sentence quote cannot do that, so this variant wraps
   normally and takes the narrower measure the reference uses. */
.m__ltext--quote { padding-top: 80px; padding-bottom: 80px; }
/* .m__ltext .u__wrap sets 1344px later in this file at equal specificity,
   so the variant is qualified with .m__ltext to outrank it in place. */
.m__ltext.m__ltext--quote .u__wrap { max-width: 1000px; }
.m__ltext.m__ltext--quote .m__ltext__copy {
  white-space: normal;
  text-align: center;
  margin-bottom: 24px;
}
.m__ltext__quote { margin: 0; }
.m__ltext__cite { text-align: center; }
/* <footer> inside <blockquote> is the attribution; the em dash is decorative
   so it lives in CSS rather than the text node a screen reader announces. */
.m__ltext__cite::before { content: "\2014\00a0 "; }

/* m__llist__grid is 3-up at xl. Two cards in a 3-up track would each sit at a
   third of the wrap with a third left empty, so this variant switches to two
   equal columns. The same 1201px bound as the base grid: see the note there on
   why a bare 1200px double-matches. */
@media only screen and (min-width: 1201px) {
  .m__llist--2up .m__llist__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
/* Wider columns than the 3-up case, so the frame gets proportionate height. */
@media only screen and (min-width: 1201px) {
  .m__llist--2up .m__llist__card-highlight { height: 440px; }
}
/* The section heading here is .m__menus__title, whose spacing rule targets
   `+ .card-grid`. This grid is m__llist__grid, so it needs its own. */
.m__menus__title + .m__llist__grid { margin-bottom: 0; }

/* Back to the location index from a venue's menu page. */
.menu-back-link { margin-top: -32px; margin-bottom: 16px; }
.menu-back-link a { text-decoration: none; }
.menu-back-link a:hover,
.menu-back-link a:focus-visible { text-decoration: underline; }

@media only screen and (max-width: 1200px) {
  .m__ltext--quote { padding-top: 48px; padding-bottom: 48px; }
}

/* ---- PRIVATE EVENTS pages ---- */
/* The reference event pages reuse the modules already in this sheet
   (m__hero, m__ltext, m__fmedia, m__pslider, m__map, contact-form). Only the
   pieces below have no existing equivalent: the standalone section heading,
   the venue at-a-glance list, the capability strip and the two list blocks. */

/* Standalone section heading. .m__menus__title centres its heading and owns a
   `+ .card-grid` spacing rule, which does not apply where the next element is
   a plain list or an fmedia row, so these pages use their own. */
/* Left-aligned, matching "S&W Regional Footprint" on the home page: every
   section heading on these pages sits on the same vertical as the page
   gutter rather than some centred and some not. */
.pe__section-title { text-align: left; margin-bottom: var(--space-2xl); }

/* These two use the shared .m__menus__title, which stays centred for the
   per-venue menu pages' own headings. Scoped by id so only these move. */
#menus-by-location,
#our-locations { text-align: left; }
/* The slider headings use .m__pslider__title's own 50px margin instead, so
   they sit identically to the home page's "S&W Regional Footprint". */
.pe__section-head { padding-top: 40px; }

/* Venue at-a-glance: the reference page sets three short points under the
   hero, then a capability strip. Both are lists, so list-style is dropped
   rather than the markup being flattened to paragraphs. */
.pe__venue-intro { padding-top: 40px; padding-bottom: 80px; text-align: center; }
.pe__venue-points,
.pe__venue-specs,
.pe__functions-list { list-style: none; margin: 0; padding: 0; }
.pe__venue-points { max-width: 760px; margin: 0 auto var(--space-xl); }
/* The at-a-glance figures are all still pending, so this framing sentence —
   the reference page's own — carries the section while they are TBD. */
.pe__venue-lede { max-width: 820px; margin: 0 auto var(--space-lg); }
.pe__venue-points li { margin-bottom: var(--space-sm); }
.pe__venue-points li:last-child { margin-bottom: 0; }

/* Capability strip — A/V, WI-FI, CAPACITY. Inline row on wide screens,
   separated by gold rules; flex-wrap lets it fall to two lines rather than
   overflow, and the rules are drawn on the item so a wrapped line does not
   start with a stray divider. */
.pe__venue-specs {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-md) 0;
  margin-bottom: var(--space-xl);
}
.pe__venue-specs li { padding: 0 var(--space-lg); }
.pe__venue-specs li + li { border-left: 1px solid #976f41; }
.pe__venue-cta { margin: 0; }

/* Events and functions: each occasion type with its own line icon. Two
   columns from the 1200px tier up so seven items do not run as one long
   ladder. The list was `columns: 2`, which cannot hold an icon in line with
   wrapping text — a fragmented item would leave its mark stranded in the
   other column — so it is a grid instead, filled down the first column then
   the second to keep reading order. */
.pe__functions { padding-bottom: 100px; }
/* The heading stays left-aligned on the page gutter; the grid itself is
   centred under it (client direction). Items keep a shared left edge inside
   each column rather than each being centred independently — the labels are
   unequal widths ("Bar" against "Conference Meetings"), so per-item centring
   would make the icon column zigzag. */
.pe__functions-list { margin-inline: auto; width: fit-content; }
.pe__functions-list li {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  margin-bottom: var(--space-sm);
}
.pe__functions-list li:last-child { margin-bottom: 0; }
/* The mark is decorative and the label carries the meaning, so the icon is
   the item that gives way: it never shrinks, and the text wraps beside it. */
.pe__functions-icon {
  flex: 0 0 auto;
  color: var(--color-gold);
  stroke-width: 1.5px;
}

/* Card eyebrow on the OUR LOCATIONS cards — the reference sets a short label
   above the venue name. Sits tight to the title it introduces. */
.m__llist__card-eyebrow { margin-top: var(--space-md); margin-bottom: var(--space-2xs); }

/* Back to the venue index from a venue's event page. .u__wrap carries the page
   gutter, so this only needs its own vertical rhythm. */
.pe__back-link { margin-top: 0; margin-bottom: 80px; }
.pe__back-link a { text-decoration: none; }
.pe__back-link a:hover,
.pe__back-link a:focus-visible { text-decoration: underline; }

/* LOCATION DETAILS heading sits inside m__map, whose own row is full-bleed;
   the heading takes the wrap, so it needs the gap to the row below. */
.m__map .pe__section-title { margin-bottom: var(--space-xl); }

@media only screen and (min-width: 1201px) {
  /* Three columns. Measured against the widest item (226px, "Conference
     Meetings"): 3 columns need 871px and the wrap offers 1104px at the
     1200px tier, so it fits with room to spare, where 4 columns would need
     1193px and overflow there. Columns are explicit so the items fill each
     row left to right, in the order the client set.
     Note this block is inside the sheet's `min-width: 1201px` tier, so the
     1101-1200px band is covered by its own rule below. */
  .pe__functions-list {
    display: grid;
    grid-template-columns: repeat(3, auto);
    column-gap: var(--space-3xl);
  }
}

/* 1101-1200px: still wide enough for three columns (871px needed against
   1104px usable at 1200px), which the sheet's 1201px tier does not reach. */
@media only screen and (min-width: 1101px) and (max-width: 1200px) {
  .pe__functions-list {
    display: grid;
    grid-template-columns: repeat(3, auto);
    column-gap: var(--space-3xl);
  }
}

/* Between 641px and 1200px three columns overflow (871px needed, 672px
   available at 768px), so the strip drops to two; below 641px a single
   column, since two need 548px. */
@media only screen and (min-width: 641px) and (max-width: 1100px) {
  .pe__functions-list {
    display: grid;
    grid-template-columns: repeat(2, auto);
    column-gap: var(--space-xl);
  }
}

@media only screen and (max-width: 1200px) {
  .pe__section-title { margin-bottom: var(--space-xl); }
  .pe__section-head { padding-top: 24px; }
  .pe__venue-intro { padding-top: 24px; padding-bottom: 48px; }
  .pe__functions { padding-bottom: 48px; }
  .pe__back-link { margin-bottom: 48px; }
  /* Stacked, the vertical rules would read as stray marks, so the strip
     becomes a column and the dividers are dropped. */
  .pe__venue-specs { flex-direction: column; }
  .pe__venue-specs li { padding: 0; }
  .pe__venue-specs li + li { border-left: 0; }
}


/* ---- PRIVATE EVENTS: the HOSPITALITY IS IN OUR BLOOD slider ---- */
/* Shares accessible tabs and motion handling with the home location slider;
   the scoped grid below follows Taiwan's Private Events image dimensions. */

/* The tab strip is a horizontal scroller below 1200px: the module sets
   flex-wrap: nowrap and white-space: nowrap there, and .m__pslider__nav-wrapper
   scrolls with its own scroll-end affordance. These three labels are longer
   than the home page's city names, so the strip does need dragging at 390px —
   left as the module intends rather than overridden, since the home page's six
   tabs rely on the same behaviour and the arrows switch panels too. */
/* Match Taiwan's panel typography, independently of the home location slider. */
.pe__hosp .m__pslider__swiper-slide-title {
  font-size: 50px;
  line-height: 140%;
  padding-top: 51px;
  padding-bottom: 57px;
  overflow-wrap: break-word;
  word-break: normal;
  hyphens: none;
}
.pe__hosp .m__pslider__swiper-slide-divider {
  width: 114px;
  max-width: 50%;
  margin-bottom: 39px;
}
@media only screen and (max-width: 1200px) {
  .pe__hosp .m__pslider__swiper-slide-title {
    font-size: 36px;
    padding-top: 0;
    padding-bottom: 24px;
  }
}

/* Hospitality follows Taiwan's grid independently of the home location slider. */
.pe__hosp > .u__wrap { padding-inline: 0; }
.pe__hosp > .u__wrap::before { display: none; }
.pe__hosp .m__pslider__swiper-slide-row {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  margin-inline: -12px;
}
.pe__hosp .m__pslider__swiper-slide-left,
.pe__hosp .m__pslider__swiper-slide-right {
  flex: 0 0 100%;
  max-width: 100%;
  padding-inline: 12px;
}
.pe__hosp .m__pslider__swiper-slide-right { order: -1; padding-bottom: 0; }
.pe__hosp .m__pslider__swiper-slide-highlight {
  height: 342px;
  margin-bottom: 24px;
}
@media only screen and (min-width: 1200px) {
  .pe__hosp .m__pslider__swiper-slide-left,
  .pe__hosp .m__pslider__swiper-slide-right {
    flex-basis: 50%;
    max-width: 50%;
  }
  .pe__hosp .m__pslider__swiper-slide-right { order: 0; }
}
@media only screen and (min-width: 1201px) {
  .pe__hosp .m__pslider__swiper-slide.swiper-slide-active { border-left: 1px solid var(--color-gold); }
  .pe__hosp .m__pslider__swiper-slide-left { padding-left: 30px; }
  .pe__hosp .m__pslider__swiper-slide-right { padding-bottom: 75px; }
  .pe__hosp .m__pslider__swiper-slide-highlight { height: 617px; margin-bottom: 0; }
  /* Keep the copy clear of the photograph's 10% extension into its column. */
  .pe__hosp .m__pslider__swiper-slide-title,
  .pe__hosp .m__pslider__swiper-slide-content { max-width: calc(100% - 60px); }
}
@media only screen and (min-width: 1400px) {
  .pe__hosp .m__pslider__swiper-slide-left {
    flex-basis: 41.6667%;
    max-width: 41.6667%;
    padding-left: 12px;
  }
}

/* ---- Form intro line — live m__ltext ---- */
/* Live section padding: 25px top / 80px bottom, 0 / 48px below 1200px. */
.m__ltext {
  padding-top: 25px;
  padding-bottom: 80px;
}
/* The live rule narrows this wrap to 888px, which is enough for the Taiwan
   page because its own copy is shorter. At 28px our sentence wrapped onto two
   lines there, so the wrap keeps the page measure and the line is held to one
   with nowrap; it drops back to normal wrapping on mobile, where one line is
   impossible. */
.m__ltext .u__wrap { max-width: 1344px; }
.m__ltext__copy { white-space: nowrap; }
@media only screen and (max-width: 1200px) {
  .m__ltext__copy { white-space: normal; }
}
.m__ltext__copy { margin: 0; }
/* .f__paragraph-large did not exist in this sheet — added from the live
   stylesheet (28px, stepping to 22px below 1200px). */
.f__paragraph-large {
  font-family: var(--font-body);
  font-style: normal;
  font-weight: 400;
  font-size: 28px;
  line-height: 180%;
}
@media only screen and (max-width: 1200px) {
  .m__ltext {
    padding-top: 0;
    padding-bottom: 48px;
  }
  .f__paragraph-large { font-size: 22px; }
}

.text-center { text-align: center; }

/* ---------------------------------------------------------------- */
/* Contact form (Locations page, bottom)                             */
/* ---------------------------------------------------------------- */
.contact-form { padding-bottom: var(--space-3xl); }
/* Live layout: fields 1-3 are col-xl-4 (three across), 4-5 are col-xl-6
   (two across), comments and submit col-12. Hand-rolled on a 6-track grid
   so both splits share one container; xl is 1200px throughout this build. */
.contact-form__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  column-gap: var(--space-lg);
}
@media only screen and (min-width: 1201px) {
  .contact-form__grid { grid-template-columns: repeat(6, minmax(0, 1fr)); }
  .form-field--third { grid-column: span 2; }
  .form-field--half { grid-column: span 3; }
  .form-field--full { grid-column: 1 / -1; }
}
.form-required-note {
  font-size: 15px;
  color: var(--color-brown);
  margin: 0 0 var(--space-lg);
}
.form-field { margin-bottom: var(--space-lg); }
/* Uppercase, matching the live Taiwan form labels. Applied in CSS rather than
   by rewriting the markup, so the accessible name keeps its natural casing for
   screen readers. */
.form-field label {
  display: block;
  font-family: var(--font-body);
  font-size: 16px;
  color: var(--color-ink);
  margin-bottom: var(--space-xs);
  text-transform: uppercase;
  letter-spacing: .04em;
}
.form-field .req { color: var(--color-brown); }
.form-field input,
.form-field select,
.form-field textarea {
  width: 100%;
  font-family: var(--font-body);
  font-size: 16px;
  padding: 0.7rem 0.85rem;
  border: 1px solid rgba(33, 37, 41, 0.3);
  background: var(--color-white);
  color: var(--color-ink);
}
.form-field input:focus-visible,
.form-field select:focus-visible,
.form-field textarea:focus-visible {
  outline: 2px solid var(--color-gold);
  outline-offset: 1px;
}
.form-field textarea { resize: vertical; min-height: 130px; }
.form-note {
  font-size: 14px;
  color: var(--color-muted);
  font-style: italic;
  margin-bottom: var(--space-lg);
}
.contact-form__submit { text-align: center; }
/* Result of the last submission, above the form. */
.form-status {
  margin: 0 0 var(--space-lg);
  padding: var(--space-md) var(--space-lg);
  border-left: 3px solid var(--color-green);
  background: #feead8;
  color: var(--color-ink);
}
.form-status--error { border-left-color: #a4262c; }
/* The section is focusable only so the #contact-form anchor lands on it. */
.contact-form:focus { outline: none; }
/* Honeypot: off-screen rather than display:none, which some bots skip. */
.form-field--hp {
  position: absolute;
  left: -10000px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* "Get Directions" — a secondary gold text link, deliberately lighter than
   the RESERVATIONS button so it does not compete with the primary CTA.
   Until each Vietnam address is confirmed it renders as a non-focusable
   pending state rather than a link to an empty map. */
/* The pending link and its note stack, but as normal flow rather than flex:
   a flex item stretches to the line and .tbd would then underline the whole
   width. ::before on the note forces the break instead. */
.directions { margin-top: var(--space-xs); }
.directions__note::before { content: ""; display: block; }
.directions__link,
.directions__pending {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2xs);
  font-family: var(--font-sans);
  font-size: 13px;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--color-gold);
}
.directions__link {
  text-decoration: underline;
  text-decoration-color: rgba(151, 111, 65, 0.45);
  text-underline-offset: 3px;
  transition: text-decoration-color var(--dur-fast) var(--ease-out);
}
.directions__link:hover { text-decoration-color: var(--color-gold); }
@media (prefers-reduced-motion: reduce) {
  .directions__link { transition-duration: 80ms; }
}
.directions__pending {
  opacity: 0.7;
  cursor: default;
  text-decoration: line-through;
  text-decoration-color: rgba(151, 111, 65, 0.5);
}
.directions__icon { flex-shrink: 0; }
/* This element is both the flex item and the .tbd carrier, so it must not be
   given a full-width box: the dashed border-bottom would paint right across
   it and read as a second separator competing with the gold rule above.
   `width: fit-content` keeps the underline on the text, while the forced line
   break before it puts the note under "Get Directions" rather than beside
   it. */
.directions__note {
  width: fit-content;
  max-width: 100%;
  margin-top: var(--space-2xs);
  font-size: 14px;
}

/* ---------------------------------------------------------------- */
/* About / Privacy — long document pages                             */
/* ---------------------------------------------------------------- */
.doc-page { max-width: 888px; margin: 0 auto; }
.doc-page h1 { margin-bottom: var(--space-xl); }
.doc-page h2 { margin: var(--space-2xl) 0 var(--space-md); }
.doc-page p { color: var(--color-muted); margin: 0 0 var(--space-md); }
.doc-page ol { margin: 0 0 var(--space-lg); padding-left: 1.4rem; color: var(--color-muted); }
.doc-page ol li { margin-bottom: var(--space-sm); }
.doc-page ul { margin: 0 0 var(--space-lg); padding-left: 1.4rem; list-style: square; color: var(--color-muted); }
.doc-page ul li { margin-bottom: var(--space-sm); }
.privacy-page__lead { text-align: center; margin-bottom: var(--space-2xl); }
.doc-page p.privacy-page__lead { color: var(--color-green); }
.doc-page p.privacy-page__lead + p:not(.privacy-page__lead) { margin-top: var(--space-2xl); }
.doc-page strong { color: var(--color-ink); }
/* About Us: the same gap above and below the copy, set here alone so
   Elementor's widget spacing does not add to it. */
.section.about-copy { padding-block: var(--space-xl) 0; }
.about-copy .doc-page p:last-child { margin-bottom: 0; }
.elementor-widget:has(.about-copy) { margin-bottom: 0 !important; }
/* About Us photo: spans the paragraph column, scales with it. */
/* Same box as .u__wrap.doc-page (888px including the wrap's side padding),
   so the photo lines up with the text edges. The sibling selector also
   catches an Image widget added by hand without the class. */
.swvn-about-image,
.elementor-widget:has(.about-copy) + .elementor-widget-image { box-sizing: border-box; width: 100%; max-width: 888px; margin: 0 auto; padding: var(--space-xl) 48px var(--space-3xl); }
@media only screen and (max-width: 1200px) {
  .swvn-about-image,
  .elementor-widget:has(.about-copy) + .elementor-widget-image { padding-inline: 24px; }
}
.swvn-about-image img,
.elementor-widget:has(.about-copy) + .elementor-widget-image img { display: block; width: 100%; max-width: none; height: auto; }
/* Elementor caps container widgets with ".elementor.elementor .e-con >
   .elementor-widget { max-width: 100% }", which outranks the rule above. */
.elementor.elementor .e-con > .elementor-widget.swvn-about-image,
.elementor.elementor .e-con > .elementor-widget:has(.about-copy) + .elementor-widget-image { max-width: 888px; }

/* ---------------------------------------------------------------- */
/* Footer — live geometry                                             */
/* ---------------------------------------------------------------- */
/* Live padding is `80px 48px 150px`, where the 150px bottom reserved room for
   the absolutely-positioned watermark. The watermark is now in flow, so that
   reserve is no longer needed. */
.footer,
.site-footer {
  width: 100%;
  background-color: #005b28;
  padding: 80px 48px 40px;
  overflow: hidden;
  position: relative;
}
.footer .u__wrap,
.site-footer .u__wrap { padding-inline: 0; }

.footer__row {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  margin-inline: -12px;
}
.footer__col {
  flex: 0 0 100%;
  padding-inline: 12px;
  min-width: 0;
}
.footer__col-item { margin-bottom: 15px; }
.footer__col-item p { margin: 0 0 15px; }
.footer__col-item p:last-child { margin-bottom: 0; }
.footer__col-link { display: inline-block; }
/* Address / telephone / email each own a line. */
.footer__col-link-ignite { display: block; }
.footer__contact-link { color: inherit; text-decoration: none; }
.footer__contact-link:hover { text-decoration: underline; }
.footer__contact-link:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; }
.footer__col-link { transition: opacity .25s ease; }
.footer__col-link:hover { color: #fff; opacity: 0.75; }
.footer__col-inline { display: inline-block; padding-right: 1rem; }

.footer__social {
  display: flex;
  justify-content: flex-start;
  gap: 0;
}
.footer__social .social-link {
  color: #fff;
  margin-right: 15px;
  display: inline-flex;
  width: 40px;
  height: 40px;
  align-items: center;
  justify-content: center;
  transition: color .25s ease, opacity .25s ease;
}
.footer__social .social-link:hover,
.footer__social .social-link:focus-visible {
  color: var(--color-gold);
}

/* The live site absolutely positions this watermark at bottom:-35px and relies
   on the footer's 150px bottom padding to clear it. That breaks once the
   content column wraps taller than the padding reserves — the copyright then
   sits on top of the wordmark (measured 68px of overlap at 1600px wide).
   Keeping it in normal flow after the content guarantees it always sits below
   the footer text and stays fully visible, at any width. */
.footer__logo {
  width: 100%;
  max-width: 1344px;
  margin: var(--space-xl) auto 0;
  height: 103px;
  pointer-events: none;
}
.footer__logo img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  object-position: center bottom;
  display: block;
}

@media (min-width: 1200.01px) {
  .footer__col--links { flex: 0 0 75%; }
  .footer__col--social { flex: 0 0 25%; }
  .footer__col--social .footer__social { justify-content: flex-end; }
  .footer__col--copyright { flex: 0 0 25%; }
}
@media (max-width: 1200px) {
  .footer, .site-footer { padding-left: 24px; padding-right: 24px; }
  .footer__col { margin-bottom: 30px; }
  .footer__logo { height: 56px; width: 100%; margin-top: var(--space-lg); }
  .footer__col-inline { display: block; padding-right: 0; }
}

/* ---------------------------------------------------------------- */
/* The People Behind — leadership portfolio, 3-up                    */
/* ---------------------------------------------------------------- */
.m__team { margin-bottom: 120px; }
.m__team__title { margin-bottom: 50px; }
.m__team__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 56px var(--space-xl);
  margin: 0;
  padding: 0;
  list-style: none;
}
@media only screen and (min-width: 768px) {
  .m__team__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media only screen and (min-width: 1201px) {
  .m__team__grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
/* The portraits arrive at different crops; a 4:5 frame anchored near the
   top keeps every face at the same height across the row. */
.m__team__photo {
  aspect-ratio: 4 / 5;
  overflow: hidden;
  margin-bottom: 32px;
  background-color: var(--color-cream-soft);
}
.m__team__photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 20%;
  display: block;
}
.m__team__name { margin: 0 0 8px; font-size: 20px; }
.m__team__role { margin: 0; font-weight: 700; }
.m__team__company { margin: 0; }
.m__team__divider {
  height: 1px;
  width: 115px;
  background-color: #976f41;
  margin: 20px 0;
}
.m__team__bio { margin: 0; }
@media only screen and (max-width: 1200px) {
  .m__team { margin-bottom: 48px; }
  .m__team__title { margin-bottom: 24px; }
}

/* A logo in place of a photograph: never crop it, at any width. */
.m__fmedia__media--contain { background-color: #fff; }
.m__fmedia__media--contain img { object-fit: contain; }
@media (max-width: 1200px) {
  .m__fmedia__media--contain { height: auto; }
  .m__fmedia__media--contain img { height: auto; object-fit: contain; }
}

/* ---------------------------------------------------------------- */
/* Home page intro â€” after the Taiwan site's preloader. A cream       */
/* screen shows the welcome line, a 400px window opens onto the hero, */
/* then the panels slide out and the top band settles into the       */
/* header. Classes are added in sequence by main.js (initHomeIntro).  */
/* ---------------------------------------------------------------- */
.swvn-intro { display: none; }
.swvn-intro-hold { overflow: hidden; }
.swvn-intro-hold .m__hero__overlay { opacity: 0; }
.swvn-intro-on .swvn-intro {
  display: block;
  position: fixed;
  inset: 0;
  z-index: 21;
  overflow: hidden;
  /* GSAP's default ease (power1.out), which the Taiwan timeline uses. */
  --swvn-intro-ease: cubic-bezier(.25, .46, .45, .94);
}
.swvn-intro__row { display: flex; height: 100%; }
.swvn-intro__panel { background-color: #feead8; }
.swvn-intro__panel--left,
.swvn-intro__panel--right {
  flex: none;
  width: calc(50% - 200px);
  transition: transform 1.5s var(--swvn-intro-ease), background-color 1s var(--swvn-intro-ease) .5s, opacity .5s var(--swvn-intro-ease) 1s;
}
.swvn-intro__panel--middle { flex: none; width: 400px; transition: opacity .5s var(--swvn-intro-ease); }
.swvn-intro__panel--top,
.swvn-intro__panel--bottom {
  position: absolute;
  left: 0;
  width: 100%;
  height: 200px;
}
.swvn-intro__panel--top {
  top: 0;
  transition: height .5s var(--swvn-intro-ease), background-color 1s var(--swvn-intro-ease), opacity .25s var(--swvn-intro-ease) .3s;
}
.swvn-intro__panel--bottom {
  bottom: 0;
  transition: transform 1.5s var(--swvn-intro-ease), background-color 1s var(--swvn-intro-ease) .5s, opacity .5s var(--swvn-intro-ease) 1s;
}
.swvn-intro__text {
  position: absolute;
  inset: 0;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 0 16px;
  text-align: center;
}
.swvn-intro__subtitle,
.swvn-intro__title { color: #976f41; opacity: 0; }
.swvn-intro__subtitle { letter-spacing: .25em; transition: opacity .5s var(--swvn-intro-ease), color .5s var(--swvn-intro-ease); }
.swvn-intro__title { transition: opacity .5s var(--swvn-intro-ease) .5s, color .25s var(--swvn-intro-ease); }
/* Step 1: the welcome line fades in, subtitle then title. */
.swvn-intro.is-text .swvn-intro__subtitle,
.swvn-intro.is-text .swvn-intro__title { opacity: 1; }
/* Step 2: the middle panel opens a window onto the hero. */
.swvn-intro.is-open .swvn-intro__panel--middle { opacity: 0; }
.swvn-intro.is-open .swvn-intro__subtitle { color: #fff; }
/* Step 3: the panels slide out; the top band becomes the header. */
.swvn-intro.is-expand .swvn-intro__title { color: #fff; }
.swvn-intro.is-expand .swvn-intro__panel--top {
  height: var(--swvn-intro-header, 169px);
  background-color: #fff;
  opacity: 0;
}
.swvn-intro.is-expand .swvn-intro__panel--left,
.swvn-intro.is-expand .swvn-intro__panel--right,
.swvn-intro.is-expand .swvn-intro__panel--bottom { background-color: #fff; opacity: 0; }
/* A fixed 1200px, as on the Taiwan site, so the sides clear the screen well
   before the 1.5s is up; a percentage of the panel's own width is far slower. */
.swvn-intro.is-expand .swvn-intro__panel--left { transform: translateX(-1200px); }
.swvn-intro.is-expand .swvn-intro__panel--right { transform: translateX(1200px); }
.swvn-intro.is-expand .swvn-intro__panel--bottom { transform: translateY(100%); }
