/* ============================================================================
   Ducey's on the Lake — components Bootstrap does not ship
   ----------------------------------------------------------------------------
   Layout, spacing and every component that exists in Bootstrap comes from
   Bootstrap. This file is only the pieces it has no equivalent for: the Ken
   Burns hero, the full-bleed venue bands, the leadered menu sheet, the history
   timeline. Anything that could be a utility class is a utility class.
============================================================================ */

/* ==========================================================================
   HERO — crossfading Ken Burns stack standing in for a video plate
   --------------------------------------------------------------------------
   basslake.com has no hero video, so rather than ship a black <video> that
   never plays, the hero runs a slow zoom and crossfade over the resort's own
   photography. It reads as motion at a fraction of the weight.
   ========================================================================== */
.hero { position: relative; min-height: 100svh; overflow: hidden; }
.hero-media { position: absolute; inset: 0; }

/* THE FOCUS PULL
   --------------------------------------------------------------------------
   The incoming picture arrives soft and slightly drained, then resolves: the
   blur clears and the colour comes up. It reads like a lens finding focus, it
   is not a zoom, and it draws the eye to the photograph rather than sliding it
   around.

   Built on transitions, NOT keyframes, and that is deliberate. The previous
   version wiped the image in behind an animated mask, and the animation ended
   at a mask position that left part of the frame outside the mask entirely.
   With `animation-fill-mode: both` that final frame persisted, so the hero got
   stuck showing half a picture. A transition cannot do that: its resting state
   is whatever the class says, so the worst an interrupted transition can do is
   arrive early.

   Nothing here scales, and both properties are compositor-friendly. */
.hero-slide {
  position: absolute; inset: 0;
  background-size: cover; background-position: center;
  opacity: 0;
  filter: blur(16px) saturate(.5);
  transform: scale(1.02);          /* hides the blur's soft edge, does not animate */
  transition: opacity 1.7s var(--duceys-ease), filter 2.4s var(--duceys-ease);
  will-change: opacity, filter;
}
.hero-slide.active {
  opacity: 1;
  filter: blur(0) saturate(1);
  animation: hero-drift 11s linear infinite alternate;
}

/* the drift is transform-only, so its resting value can never hide anything */
@keyframes hero-drift {
  from { transform: scale(1.02) translate3d(-1.4%, 0, 0); }
  to   { transform: scale(1.02) translate3d(1.4%, 0, 0); }
}

/* a slow light crossing the frame, so the picture is never quite still */
.hero-media::after {
  content: ''; position: absolute; inset: -20%;
  background: linear-gradient(74deg, transparent 42%, rgba(255, 236, 190, .1) 50%, transparent 58%);
  animation: hero-sheen 11s ease-in-out infinite;
  pointer-events: none;
}
@keyframes hero-sheen {
  0%, 100% { transform: translate3d(-28%, 0, 0); opacity: 0; }
  45%      { opacity: 1; }
  60%      { transform: translate3d(28%, 0, 0); opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .hero-slide { transition: none; filter: none; }
  .hero-slide.active { animation: none; }
  .hero-media::after { animation: none; opacity: 0; }
}
.hero-scrim {
  position: absolute; inset: 0; z-index: 2;
  background:
    linear-gradient(180deg, rgba(4, 16, 31, .82) 0%, rgba(4, 16, 31, .45) 38%, rgba(4, 16, 31, .92) 100%),
    linear-gradient(90deg, rgba(4, 16, 31, .55), transparent 55%);
}
.hero h1 { font-size: clamp(2.6rem, 7vw, 6rem); }
.hero-meta li {
  font-size: .7rem; letter-spacing: .28em; text-transform: uppercase;
  color: rgba(246, 241, 231, .8);
}
.hero-meta li::before { content: '•'; color: var(--duceys-gold); margin-right: .6rem; }

.scroll-cue {
  position: absolute; bottom: 2.2rem; left: 50%; transform: translateX(-50%);
  z-index: 3; text-align: center;
}
.scroll-cue span {
  display: block; font-size: .6rem; letter-spacing: .3em;
  text-transform: uppercase; color: var(--duceys-stone); margin-bottom: .6rem;
}
.scroll-cue i {
  display: block; width: 1px; height: 46px; margin-inline: auto;
  background: linear-gradient(var(--duceys-gold), transparent);
}

/* ==========================================================================
   VENUE BANDS — full-bleed photograph with the copy held in a Bootstrap row
   ========================================================================== */
.venue {
  position: relative; overflow: hidden;
  padding-block: clamp(5rem, 12vw, 9.5rem);
  border-bottom: 1px solid rgba(246, 241, 231, .08);
}
.venue-bg {
  position: absolute; inset: -12% 0; z-index: 0;
  background-size: cover; background-position: center;
  will-change: transform;
}
/* Crossed gradients: bottom-up for the copy block, left-to-right so the text
   still holds when the photograph is bright on that side. */
.venue::after {
  content: ''; position: absolute; inset: 0; z-index: 1;
  background:
    linear-gradient(180deg, rgba(4, 16, 31, .55), rgba(4, 16, 31, .88)),
    linear-gradient(90deg, rgba(4, 16, 31, .92), rgba(4, 16, 31, .25) 62%);
}
.venue > .container { z-index: 2; }
.venue-index {
  font-size: .62rem; letter-spacing: .32em; text-transform: uppercase;
  color: var(--duceys-gold); font-weight: 700;
}
.venue-kicker { color: var(--duceys-gold); font-size: .95rem; margin-block: .6rem 1.2rem; }
.venue-copy { color: #DCE4EF; max-width: 54ch; }
.venue-hours { display: flex; flex-direction: column; gap: .35rem; margin-top: 1.6rem; }
.venue-hours span { font-size: .84rem; color: var(--duceys-stone); }
.venue-hours b { color: var(--duceys-cream); font-weight: 400; margin-right: .5rem; }

/* ==========================================================================
   QUOTE BREAK
   ========================================================================== */
.parallax-break { position: relative; overflow: hidden; min-height: 60vh; }
.parallax-break::after {
  content: ''; position: absolute; inset: 0; z-index: 1;
  background: rgba(4, 16, 31, .8);
}
.parallax-break > .container { z-index: 2; }
.parallax-break blockquote p {
  font-family: var(--duceys-display); font-style: italic;
  max-width: 22ch; margin-inline: auto;
}
.parallax-break cite { color: var(--duceys-stone); font-style: normal; }

/* ==========================================================================
   THE MENU
   --------------------------------------------------------------------------
   Two independent columns rather than a CSS `columns` flow: a row expanding on
   click must never re-balance the whole menu, which is what threw courses from
   one column to the other under the reader's cursor.
   ========================================================================== */
.menu-switch { gap: clamp(1.2rem, 3vw, 2.8rem); margin-top: 3.2rem; }
.menu-switch-btn {
  background: none; border: 0; cursor: pointer;
  font-family: var(--duceys-display);
  font-size: clamp(1.35rem, 3vw, 2.1rem);
  color: rgba(246, 241, 231, .3);
  padding-bottom: .4rem;
  transition: color .4s var(--duceys-ease);
}
.menu-switch-btn:hover { color: rgba(246, 241, 231, .7); }
.menu-switch-btn.on { color: var(--duceys-gold); }

/* the gold rule that slides between services, positioned from JS because the
   labels are different widths and the switcher is centred */
.switch-ink {
  position: absolute; bottom: 0; left: 0; height: 1px; width: 0;
  background: var(--duceys-gold); pointer-events: none; opacity: 0;
  transition: transform .55s var(--duceys-ease), width .55s var(--duceys-ease), opacity .3s;
}
.switch-ink.on { opacity: 1; }

.menu-hours {
  margin-top: 1.1rem; font-size: .74rem; letter-spacing: .18em;
  text-transform: uppercase; color: var(--duceys-stone);
}
.menu-sheet { margin-top: 4rem; }
.sheet-cols {
  display: grid; grid-template-columns: 1fr 1fr;
  gap: 0 clamp(2.5rem, 6vw, 5.5rem); align-items: start;
}
.sheet-col { min-width: 0; }
@media (max-width: 991.98px) { .sheet-cols { grid-template-columns: 1fr; } }

.course { margin-bottom: 3.2rem; }
.course-wide { margin-bottom: 0; }
.course h3 {
  font-size: 1.6rem; color: var(--duceys-gold);
  padding-bottom: .7rem; margin-bottom: 1rem;
  border-bottom: 1px solid rgba(255, 205, 42, .28);
}
.course-note { font-size: .84rem; line-height: 1.55; color: var(--duceys-stone); margin-bottom: 1.2rem; }

/* Every dish leads with a tile so the column keeps one rhythm and the leaders
   line up. Small on purpose: this is a menu you read, not a gallery. */
.mrow {
  padding: .55rem 0;
  display: grid; grid-template-columns: 64px minmax(0, 1fr); gap: .95rem;
  align-items: start; cursor: pointer; border-radius: 2px;
  scroll-margin-top: 110px;
  transition: background-color .35s var(--duceys-ease), padding .35s var(--duceys-ease);
}
.mrow:hover { background: rgba(255, 255, 255, .038); }
.mrow:hover .nm { color: #fff; }
.mrow:focus-visible { outline: 1px solid var(--duceys-gold); outline-offset: 3px; }
.mrow-body { min-width: 0; }
.mrow-top { display: flex; align-items: baseline; gap: .6rem; }
.nm { font-size: 1rem; color: var(--duceys-cream); }
.leader { flex: 1; border-bottom: 1px dotted rgba(169, 180, 196, .4); transform: translateY(-4px); }
.pr { font-family: var(--duceys-display); font-size: 1.05rem; color: var(--duceys-gold); white-space: nowrap; }
.ds { margin: .25rem 0 0; font-size: .84rem; line-height: 1.55; color: var(--duceys-stone); }

.thumb {
  width: 64px; height: 64px; margin: .1rem 0 0;
  overflow: hidden; border: 1px solid rgba(255, 205, 42, .22);
  background: rgba(255, 255, 255, .03);
}
.thumb img {
  display: block; width: 100%; height: 100%; object-fit: cover;
  filter: saturate(.95) brightness(.9);
  transition: transform .9s var(--duceys-ease), filter .9s var(--duceys-ease);
}
.mrow:hover .thumb img { transform: scale(1.07); filter: saturate(1.05) brightness(1); }
.thumb-mark {
  display: grid; place-items: center; font-size: 1.6rem; line-height: 1; opacity: .9;
  background:
    radial-gradient(120% 120% at 50% 0%, rgba(255, 205, 42, .1), transparent 72%),
    rgba(255, 255, 255, .035);
}

/* the open/close mark at the end of the price line */
.mk {
  position: relative; flex-shrink: 0; width: 11px; height: 11px; margin-left: .15rem;
  opacity: .38; transition: opacity .3s var(--duceys-ease), transform .45s var(--duceys-ease);
}
.mk::before, .mk::after {
  content: ''; position: absolute; inset: 0; margin: auto; background: var(--duceys-gold);
}
.mk::before { width: 11px; height: 1px; }
.mk::after  { width: 1px; height: 11px; transition: opacity .35s var(--duceys-ease); }
.mrow:hover .mk { opacity: .85; }
/* 180, not 90: a quarter turn stands the horizontal stroke on its end and
   hiding the other one then leaves a vertical bar rather than a minus */
.mrow.open .mk { opacity: 1; transform: rotate(180deg); }
.mrow.open .mk::after { opacity: 0; }

/* an opened dish: the tile becomes a plate and the description gets room */
.mrow.open {
  grid-template-columns: minmax(0, 1fr);
  background: rgba(255, 255, 255, .05);
  padding: 1rem 1rem 1.2rem; margin: .5rem 0;
}
.mrow.open .thumb {
  width: 100%; height: auto; aspect-ratio: 16 / 10;
  margin: 0 0 1.05rem; border-color: rgba(255, 205, 42, .32);
}
.mrow.open .thumb-mark { font-size: 3.4rem; }
.mrow.open .nm { font-size: 1.32rem; color: #fff; }
.mrow.open .pr { font-size: 1.25rem; }
.mrow.open .ds { margin-top: .5rem; font-size: .95rem; line-height: 1.7; color: rgba(246, 241, 231, .82); }
/* Never transition width px -> % alongside aspect-ratio; Chrome sticks on the
   start value. The size change is instant and the image carries the reveal. */
.mrow.open .thumb img { animation: plate-in .5s var(--duceys-ease) both; }
@keyframes plate-in { from { opacity: 0; transform: scale(1.06); } to { opacity: 1; transform: none; } }

@media (max-width: 575.98px) {
  .mrow { grid-template-columns: 52px minmax(0, 1fr); gap: .75rem; }
  .thumb { width: 52px; height: 52px; }
  .menu-switch { gap: 1.15rem; margin-top: 2.4rem; }
  .menu-switch-btn { font-size: 1.05rem; }
}
@media (prefers-reduced-motion: reduce) {
  .mrow, .thumb img, .switch-ink { transition: none; }
  .mrow:hover .thumb img { transform: none; }
  .mrow.open .thumb img { animation: none; }
}

/* ==========================================================================
   GALLERY
   --------------------------------------------------------------------------
   A dense mosaic rather than a uniform grid: equal tiles make twenty good
   photographs look like a stock library. Portrait frames span two rows so the
   composition survives instead of being centre-cropped to a landscape box.
   ========================================================================== */
.gallery-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
  grid-auto-rows: 150px;
  gap: 10px;
}
.gal {
  padding: 0; border: 0; background: none; cursor: pointer;
  grid-row: span 2; overflow: hidden; position: relative;
  border: 1px solid rgba(246, 241, 231, .08);
}
.gal-tall { grid-row: span 3; }
.gal img {
  width: 100%; height: 100%; object-fit: cover; display: block;
  filter: saturate(.92) brightness(.9);
  transition: transform 1.1s var(--duceys-ease), filter .7s var(--duceys-ease);
}
.gal:hover img, .gal:focus-visible img { transform: scale(1.06); filter: saturate(1.04) brightness(1.04); }
.gal:focus-visible { outline: 1px solid var(--duceys-gold); outline-offset: 3px; }
/* a gold corner that draws in on hover, so a tile reads as openable */
.gal::after {
  content: ''; position: absolute; inset: auto 0 0 0; height: 2px;
  background: var(--duceys-gold);
  transform: scaleX(0); transform-origin: left;
  transition: transform .5s var(--duceys-ease);
}
.gal:hover::after, .gal:focus-visible::after { transform: scaleX(1); }

@media (max-width: 575.98px) {
  .gallery-grid { grid-template-columns: repeat(2, 1fr); grid-auto-rows: 112px; gap: 8px; }
}

/* ---- the lightbox -------------------------------------------------------
   Bootstrap's default backdrop is 50% black, which over a bright photograph
   leaves the page showing through and the caption hard to read. This one is
   near-solid and blurred, so the picture is the only thing in the room. */
.gal-modal { --bs-backdrop-opacity: 1; }
.modal-backdrop.show { opacity: 1; }
.gal-modal + .modal-backdrop,
.modal-backdrop {
  background: rgba(3, 9, 18, .92);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}
.gal-modal .modal-content {
  background: transparent; border: 0; align-items: center; box-shadow: none;
}
.gal-modal .modal-dialog { padding-top: 3.4rem; }
.gal-modal .gal-full {
  max-width: 100%; max-height: 74vh; width: auto; height: auto;
  border: 1px solid rgba(255, 205, 42, .3);
  box-shadow: 0 30px 90px -30px rgba(0, 0, 0, .9);
}
.gal-modal .gal-cap {
  margin: 1.1rem auto 0; text-align: center;
  font-size: .88rem; line-height: 1.6; color: var(--duceys-cream);
  max-width: 62ch; text-shadow: 0 1px 8px rgba(0, 0, 0, .8);
}

/* A real button, not a 16px glyph: 44px target, gold on dark, always over the
   picture rather than floated above it where a phone would cut it off. */
.gal-modal .btn-close {
  position: absolute; top: 0; right: .25rem; z-index: 3;
  width: 44px; height: 44px; opacity: 1; padding: 0;
  border: 1px solid rgba(255, 205, 42, .45); border-radius: 50%;
  background: rgba(4, 16, 31, .9) no-repeat center/16px 16px;
  background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23FFCD2A'%3e%3cpath d='M.293.293a1 1 0 0 1 1.414 0L8 6.586 14.293.293a1 1 0 1 1 1.414 1.414L9.414 8l6.293 6.293a1 1 0 0 1-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 0 1-1.414-1.414L6.586 8 .293 1.707a1 1 0 0 1 0-1.414z'/%3e%3c/svg%3e");
  transition: background-color .3s, border-color .3s, transform .3s var(--duceys-ease);
}
.gal-modal .btn-close:hover { background-color: var(--duceys-gold); border-color: var(--duceys-gold); transform: rotate(90deg); }
.gal-modal .btn-close:hover { background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%2306152C'%3e%3cpath d='M.293.293a1 1 0 0 1 1.414 0L8 6.586 14.293.293a1 1 0 1 1 1.414 1.414L9.414 8l6.293 6.293a1 1 0 0 1-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 0 1-1.414-1.414L6.586 8 .293 1.707a1 1 0 0 1 0-1.414z'/%3e%3c/svg%3e"); }
.gal-modal .btn-close:focus-visible { outline: 2px solid var(--duceys-gold); outline-offset: 3px; box-shadow: none; }

/* a hint that the set can be walked, on pointer devices where keys exist */
.gal-modal .gal-cap::after {
  content: '  ←  →  to browse';
  display: block; margin-top: .5rem;
  font-size: .64rem; letter-spacing: .2em; text-transform: uppercase;
  color: var(--duceys-stone);
}
@media (hover: none) { .gal-modal .gal-cap::after { content: ''; } }

@media (prefers-reduced-motion: reduce) {
  .gal img, .gal::after { transition: none; }
  .gal:hover img { transform: none; }
  .gal-modal .btn-close { transition: none; }
  .gal-modal .btn-close:hover { transform: none; }
}

/* ==========================================================================
   RESERVATIONS, BAR, TIMELINE, VISIT, FOOTER
   ========================================================================== */
.order-cta { background: linear-gradient(180deg, var(--duceys-navy-850), var(--duceys-navy-950)); }
.order-steps { display: grid; gap: 1.4rem; }
.order-step { display: grid; grid-template-columns: 42px 1fr; gap: 1.2rem; align-items: start; }
.order-step i {
  width: 42px; height: 42px; display: grid; place-items: center;
  border: 1px solid rgba(255, 205, 42, .45); border-radius: 50%;
  font-style: normal; font-family: var(--duceys-display); color: var(--duceys-gold);
}
.order-step b { display: block; font-weight: 400; color: var(--duceys-cream); }
.order-step span { font-size: .88rem; color: var(--duceys-stone); }

/* The drinks render the same `.mrow` as the dishes, so they inherit the tile,
   the hover, the open state and the +/- mark. All that is left here is the
   hairline between rows. */
.bar-list li { border-bottom: 1px solid rgba(246, 241, 231, .1); }
.bar-list li.mrow.open { border-bottom-color: transparent; }
.bar-note {
  font-size: .84rem; color: var(--duceys-stone);
  padding-left: 1.1rem; border-left: 2px solid rgba(255, 205, 42, .5);
}

.timeline { position: relative; }
.timeline::before {
  content: ''; position: absolute; left: 7px; top: 8px; bottom: 8px; width: 1px;
  background: linear-gradient(var(--duceys-gold-deep), rgba(201, 154, 22, .12));
}
.tl-item { display: grid; grid-template-columns: 15px 1fr; gap: 1.9rem; padding: 1.4rem 0; }
.tl-dot {
  width: 15px; height: 15px; border-radius: 50%;
  border: 1px solid var(--duceys-gold); background: #0A1526; margin-top: .55rem;
}
.tl-year { font-family: var(--duceys-display); font-size: 1.6rem; color: var(--duceys-gold); line-height: 1; }
.timeline p { margin: .4rem 0 0; font-size: .9rem; color: var(--duceys-stone); }

.visit-card {
  --bs-card-bg: rgba(255, 255, 255, .03);
  --bs-card-border-color: rgba(246, 241, 231, .12);
  --bs-card-spacer-y: 1.8rem;
  --bs-card-spacer-x: 1.6rem;
}
.visit-card .card-title { font-size: 1.25rem; color: var(--duceys-gold); }
.visit-card .card-text { font-size: .92rem; color: var(--duceys-stone); }
/* :not(.btn) matters. A bare `.visit-card a` is specificity (0,1,1) and beats
   `.btn` at (0,1,0), so it repainted the Groups button's label cream — cream on
   gold is 1.75:1, against the 4.5:1 minimum. Buttons carry their own colour
   from --bs-btn-color and must be left alone. */
.visit-card a:not(.btn) { color: var(--duceys-cream); }
.visit-card a:not(.btn):hover { color: var(--duceys-gold); }

.site-footer {
  background: #030B16; padding-block: clamp(3rem, 6vw, 4.5rem);
  border-top: 1px solid rgba(246, 241, 231, .1);
}
.footer-bottom {
  border-top: 1px solid rgba(246, 241, 231, .08);
  font-size: .78rem; color: var(--duceys-stone);
}

/* On a phone the footer stacks, and left-aligned in a 375px column it read as
   three orphaned fragments with the button stranded at the edge. Centred, and
   the CTA takes the full width so it is a target rather than a link. */
@media (max-width: 767.98px) {
  .site-footer { text-align: center; }
  .footer-cta { width: 100%; justify-content: center; }
  .footer-bottom { gap: .75rem !important; line-height: 1.7; }
  .footer-bottom span, .footer-bottom a { display: block; }
}

/* ==========================================================================
   SCROLL REVEALS
   ========================================================================== */
[data-reveal] { opacity: 0; transform: translateY(26px); }
[data-reveal].in {
  opacity: 1; transform: none;
  transition: opacity .9s var(--duceys-ease), transform .9s var(--duceys-ease);
}
[data-reveal-delay="1"].in { transition-delay: .12s; }
[data-reveal-delay="2"].in { transition-delay: .24s; }
[data-reveal-delay="3"].in { transition-delay: .36s; }
@media (prefers-reduced-motion: reduce) {
  [data-reveal] { opacity: 1; transform: none; }
}
