/* =============================================================================
   main.css
   =============================================================================
   Everything Tailwind's Play CDN cannot express: the depth-gradient system,
   the scroll-driven depth rail, cross-document page transitions, focus
   treatment, and the reduced-motion contract.

   Layout and spacing stay in Tailwind utilities in the HTML. Only structural
   and systemic things live here, so there is exactly one place to look when
   something behaves oddly rather than two places that fight.
   ========================================================================== */

/* -----------------------------------------------------------------------------
   1. TOKENS
   The palette is also declared in each page's inline `tailwind.config` so the
   utility classes exist. These custom properties are the source of truth for
   everything in this file. Keep the two in sync if you change a colour.
   -------------------------------------------------------------------------- */
:root {
  /* Depth palette — reads top (surface) to bottom (abyss) */
  --surface: #f2f7f8;   /* off-white with an aqua cast — the shallows */
  --shallow: #d7ebef;
  --mid: #1f5578;       /* dark enough that white text on it clears 7:1 */
  --deep: #10294c;
  --abyss: #0a192f;     /* the brief's deep ocean blue */

  /* Accents. Each has exactly one job. */
  --coral: #d63b1e;         /* primary action. White text on this is 4.66:1 — AA. */
  --coral-bright: #ff6b4a;  /* graphics and large display only — fails AA at body size */
  --teal: #2de1c2;          /* anything that responds to you: rail, tabs, chips, focus */
  --teal-ink: #0f6f60;      /* teal that is legible as small text on white */

  /* Ink */
  --ink: #0a192f;
  --ink-soft: #4a6076;
  --ink-onDark: #e8f2f5;
  --ink-onDark-soft: #9fb8c8;

  /* Rhythm */
  --radius: 0.375rem;
  --radius-lg: 0.75rem;
}

/* -----------------------------------------------------------------------------
   2. BASE
   -------------------------------------------------------------------------- */
html {
  scroll-behavior: smooth;
  /* Offset for the sticky header when jumping to an anchor */
  scroll-padding-top: 5.5rem;
  -webkit-text-size-adjust: 100%;
}

body {
  background-color: var(--surface);
  color: var(--ink);
  font-family: Inter, ui-sans-serif, system-ui, sans-serif;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

/* Display face. Inter Tight is a genuinely different cut, not just Inter bolder,
   so headlines read as headlines without needing a second unrelated family. */
.font-display {
  font-family: 'Inter Tight', Inter, ui-sans-serif, system-ui, sans-serif;
  letter-spacing: -0.03em;
  line-height: 1.02;
}

/* Depth figures, durations, prices and counts are DATA. They align in a column
   and they never reflow as they animate. */
.tnum {
  font-variant-numeric: tabular-nums;
  font-feature-settings: 'tnum' 1;
}

/* Body copy stays readable. ~68 characters, per Bringhurst. */
.measure { max-width: 34em; }
.measure-tight { max-width: 26em; }

/* The logo is black artwork on a transparent background, and the header and
   footer are both deep navy. Rather than keeping a second white copy of the
   file in sync, this forces every non-transparent pixel to pure white and
   leaves the alpha channel alone. Drop the class to use the black original on
   a light background. */
.logo-invert { filter: brightness(0) invert(1); }

/* -----------------------------------------------------------------------------
   3. FOCUS
   Teal means "this responds to you", so teal is also what focus looks like.
   Never removed, only styled — including on dark panels.
   -------------------------------------------------------------------------- */
:focus-visible {
  outline: 2px solid var(--teal);
  outline-offset: 3px;
  border-radius: 2px;
}
.on-dark :focus-visible,
.bg-abyss :focus-visible {
  outline-color: var(--teal);
}

/* Skip link — visible the moment it is focused, invisible otherwise. */
.skip-link {
  position: absolute;
  left: 1rem;
  top: -4rem;
  z-index: 100;
  background: var(--abyss);
  color: #fff;
  padding: 0.75rem 1.25rem;
  border-radius: var(--radius);
  transition: top 0.15s ease;
}
.skip-link:focus { top: 1rem; }

/* -----------------------------------------------------------------------------
   4. THE DEPTH GRADIENT
   The page descends. Sections opt in with .depth-{zone} and the background
   carries the eye down without anyone having to think about it.
   -------------------------------------------------------------------------- */
.depth-surface {
  background: linear-gradient(180deg, var(--surface) 0%, #e9f3f5 100%);
}
.depth-shallow {
  background: linear-gradient(180deg, #e9f3f5 0%, var(--shallow) 100%);
}
/* The drop-off. Its own element rather than the top of a content section,
   because a gradient that runs light-to-dark underneath a heading gives that
   heading no single colour to be legible against. Here the transition owns a
   band of its own and every section stays either light-with-dark-text or
   dark-with-light-text. */
.depth-thermocline {
  height: 7rem;
  background: linear-gradient(180deg, var(--shallow) 0%, var(--mid) 100%);
}
/* Following a white section rather than the shallow one */
.depth-thermocline--from-surface {
  background: linear-gradient(180deg, #e9f3f5 0%, var(--mid) 100%);
}
/* Dropping straight to a .depth-deep section, which starts lower down the ramp */
.depth-thermocline--to-deep {
  background: linear-gradient(180deg, var(--shallow) 0%, var(--deep) 100%);
}

.depth-descend {
  background: linear-gradient(180deg, var(--mid) 0%, var(--deep) 100%);
}
.depth-deep {
  background: linear-gradient(180deg, var(--deep) 0%, var(--abyss) 100%);
}
.depth-abyss { background: var(--abyss); }

/* Fallback for any image slot whose URL fails. Layered gradients read as
   "water at depth" rather than as a broken asset. Applied by site.js. */
.img-fallback {
  background-color: var(--deep);
  background-image:
    radial-gradient(ellipse 120% 80% at 50% -20%, rgba(45, 225, 194, 0.28), transparent 60%),
    radial-gradient(ellipse 90% 60% at 20% 110%, rgba(10, 25, 47, 0.9), transparent 70%),
    linear-gradient(180deg, var(--mid) 0%, var(--abyss) 100%);
}
.img-fallback img { opacity: 0; }

/* -----------------------------------------------------------------------------
   5. THE DEPTH GAUGE
   A fixed dive computer that reads scroll position as metres: 0 m at the top,
   40 m at the footer. It is not decoration — it mirrors the fact that the
   content itself is ordered by depth, and its ladder is the PADI progression.

   Wide screens: the instrument, on the left.
   Everything else: a 2px progress bar under the header.
   -------------------------------------------------------------------------- */
.depth-rail {
  position: fixed;
  top: 50%;
  transform: translateY(-50%);
  width: 5.5rem;
  z-index: 30;
  display: none;
  pointer-events: none;

  /* Hugs the left edge on a narrow desktop, then tracks the content container's
     edge once the window is wider than the container — otherwise it would drift
     off alone in the margin on a large monitor while the text sat far to its
     right. 42rem is half the 84rem container. */
  left: max(0.75rem, calc(50vw - 42rem + 0.75rem));

  /* No mix-blend-mode. The old hairline version used difference blending, which
     turned the teal line orange over blue water — the instrument carries its own
     dark background instead, so its colours are its own. */
}

/* A fixed element on the left of centred content needs somewhere to be, or it
   sits on top of the text. Every content container on the site shares the same
   max width, so one rule opens a lane for the instrument across all four pages.
   The hero's background is on the section rather than the container, so it stays
   full-bleed and the instrument floats over it.

   The selector is doubled — `[class]` adds specificity without adding meaning —
   because Tailwind's own `px-8` is a single class and its stylesheet is injected
   at runtime, after this file. On an even specificity score the later rule wins,
   so a single attribute selector here silently loses and the lane never opens.

   Kept at the same breakpoint as the desktop navigation, so the page gains its
   left lane and its horizontal nav at the same moment rather than in two steps. */
@media (min-width: 1024px) {
  [class*='max-w-[84rem]'][class] { padding-left: 7.5rem; }
  .depth-rail { display: block; }
}

.dr-case {
  border-radius: 0.875rem;
  padding: 0.75rem 0.5rem 0.5rem;
  background: linear-gradient(180deg, #0f1620 0%, #05070b 100%);
  border: 1px solid rgba(255, 255, 255, 0.14);
  box-shadow: 0 12px 30px -10px rgba(0, 0, 0, 0.75);
  text-align: center;
}

.dr-label {
  font-size: 0.5625rem;
  letter-spacing: 0.1em;
  color: #8fa3b5;          /* 7.8:1 on the panel */
  line-height: 1;
  margin-bottom: 0.3rem;
}

.dr-depth {
  font-family: 'Inter Tight', Inter, sans-serif;
  font-size: 1.75rem;
  font-weight: 600;
  line-height: 1;
  letter-spacing: -0.03em;
  color: #fff;
}

.dr-rule {
  height: 1px;
  background: rgba(255, 255, 255, 0.14);
  margin: 0.625rem -0.25rem;
}

/* The ladder. Deepest at the top, so the strip reads the way the page does. */
.dr-ladder {
  display: flex;
  flex-direction: column;
  gap: 0.3125rem;
}

.dr-rung {
  display: flex;
  align-items: center;
  gap: 0.375rem;
}

.dr-rung__m {
  font-size: 0.625rem;
  font-weight: 600;
  line-height: 1;
  width: 1.15rem;
  text-align: right;
  color: #7a8fa3;          /* 6.0:1 — the dimmer grey it replaced sat at 4.37 */
  transition: color 0.25s ease;
}

.dr-rung__bar {
  flex: 1;
  height: 3px;
  border-radius: 1px;
  background: #22303d;
  transition: background-color 0.25s ease;
}

/* Lit once you have descended past that certification's depth */
.dr-rung[data-reached='true'] .dr-rung__m { color: #cfe0ee; }
.dr-rung[data-reached='true'] .dr-rung__bar { background: #3ddc84; }

/* The band names whichever certification you are currently inside the range of */
.dr-band {
  margin: 0.625rem -0.25rem -0.25rem;
  border-radius: 0 0 0.5rem 0.5rem;
  background: #9fc6e8;
  color: #05070b;
  font-size: 0.5625rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  padding: 0.25rem 0.125rem;
  line-height: 1.2;
}

/* Mobile and mid-width: the same information as a progress bar */
.depth-bar {
  position: fixed;
  left: 0;
  right: 0;
  height: 2px;
  z-index: 45;
  background: transparent;
  pointer-events: none;
}
.depth-bar__fill {
  height: 100%;
  width: 0;
  background: var(--teal);
  will-change: width;
}
@media (min-width: 1024px) {
  .depth-bar { display: none; }
}

/* -----------------------------------------------------------------------------
   6. HERO
   The one orchestrated motion moment on the site: surface light settling over
   the image as the page loads. Everything else waits for a user action.
   -------------------------------------------------------------------------- */
.hero-media { position: absolute; inset: 0; overflow: hidden; }
.hero-media img,
.hero-media video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Starts fractionally scaled and settles — one movement, then still. */
  animation: settle 2.4s cubic-bezier(0.16, 1, 0.3, 1) both;
}
@keyframes settle {
  from { transform: scale(1.06); opacity: 0; }
  to { transform: scale(1); opacity: 1; }
}

/* Caustics — the moving light you get just under the surface. Slow enough to
   register as ambience, not as an animation demanding attention. */
.hero-caustics {
  position: absolute;
  inset: -20%;
  background-image:
    radial-gradient(ellipse 45% 30% at 30% 20%, rgba(150, 240, 255, 0.16), transparent 60%),
    radial-gradient(ellipse 35% 25% at 70% 40%, rgba(45, 225, 194, 0.12), transparent 65%);
  animation: drift 24s ease-in-out infinite alternate;
  pointer-events: none;
}
@keyframes drift {
  from { transform: translate3d(-2%, -1%, 0) scale(1); }
  to { transform: translate3d(3%, 2%, 0) scale(1.08); }
}

/* Video layer. Sits above the still and fades in only once it is actually
   playing, so a blocked autoplay or a failed load simply leaves the photograph
   in place. site.js decides whether to download it at all. */
.hero-video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity 1.2s ease;
}
.hero-video.is-playing { opacity: 1; }

/* Scrim so white text over any photograph stays legible. Weighted to the
   bottom because that is where the headline sits. */
.hero-scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(
    180deg,
    rgba(10, 25, 47, 0.62) 0%,
    rgba(10, 25, 47, 0.35) 35%,
    rgba(10, 25, 47, 0.78) 100%
  );
}

/* -----------------------------------------------------------------------------
   7. CROSS-DOCUMENT PAGE TRANSITIONS
   Four real HTML pages that behave like one surface. Browsers without support
   simply navigate — nothing to detect, nothing to polyfill.
   -------------------------------------------------------------------------- */
@view-transition { navigation: auto; }

::view-transition-old(root) { animation: vt-out 0.18s ease both; }
::view-transition-new(root) { animation: vt-in 0.28s ease both; }
@keyframes vt-out { to { opacity: 0; } }
@keyframes vt-in { from { opacity: 0; } }

/* The header is the same object across pages, so it must not crossfade with
   itself — name it and it stays put while the body swaps underneath. */
.site-header { view-transition-name: site-header; }

/* -----------------------------------------------------------------------------
   8. COMPONENTS
   -------------------------------------------------------------------------- */

/* Buttons ------------------------------------------------------------------ */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  padding: 0.875rem 1.75rem;
  border-radius: var(--radius);
  font-weight: 600;
  font-size: 0.9375rem;
  line-height: 1;
  transition: background-color 0.15s ease, color 0.15s ease, border-color 0.15s ease;
  cursor: pointer;
  text-align: center;
}

/* Coral is reserved. It appears only on the action we most want taken, which
   is what makes it work. Two coral buttons on a screen would mean neither. */
.btn-primary {
  background: var(--coral);
  color: #fff;
}
.btn-primary:hover { background: #b82f15; }

.btn-ghost {
  border: 1px solid rgba(255, 255, 255, 0.5);
  color: #fff;
}
.btn-ghost:hover {
  border-color: #fff;
  background: rgba(255, 255, 255, 0.1);
}

.btn-outline {
  border: 1px solid var(--abyss);
  color: var(--abyss);
}
.btn-outline:hover { background: var(--abyss); color: #fff; }

.btn:disabled,
.btn[aria-disabled='true'] { opacity: 0.45; cursor: not-allowed; }

/* Depth bar on a dive-site card — length is the site's real max depth ------ */
.site-depth {
  height: 3px;
  background: rgba(10, 25, 47, 0.12);
  border-radius: 2px;
  overflow: hidden;
}
.site-depth__fill {
  display: block;
  height: 100%;
  background: var(--teal-ink);
  border-radius: 2px;
  /* Only animates when a filter re-plots the grid — a user action. */
  transition: width 0.4s cubic-bezier(0.16, 1, 0.3, 1);
}

/* Filter chips ------------------------------------------------------------- */
.chip {
  padding: 0.5rem 1rem;
  border-radius: 999px;
  border: 1px solid rgba(10, 25, 47, 0.18);
  font-size: 0.875rem;
  font-weight: 500;
  color: var(--ink-soft);
  transition: background-color 0.15s ease, color 0.15s ease, border-color 0.15s ease;
  cursor: pointer;
  white-space: nowrap;
}
.chip:hover { border-color: var(--abyss); color: var(--ink); }
.chip[aria-pressed='true'] {
  background: var(--abyss);
  border-color: var(--abyss);
  color: #fff;
}

/* Course tabs -------------------------------------------------------------- */
.tab {
  position: relative;
  padding: 0.875rem 0.25rem;
  font-weight: 500;
  color: var(--ink-soft);
  white-space: nowrap;
  transition: color 0.15s ease;
  cursor: pointer;
  background: none;
  border: none;
  font-size: 0.9375rem;
}
.tab:hover { color: var(--ink); }
.tab[aria-selected='true'] { color: var(--ink); font-weight: 600; }
.tab[aria-selected='true']::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1px;
  height: 2px;
  background: var(--teal-ink);
}

/* Cards — deliberately not all the same. Dive sites, courses and stats each
   get their own treatment because they hold different kinds of information. */
.card-site {
  background: #fff;
  border: 1px solid rgba(10, 25, 47, 0.08);
  border-radius: var(--radius-lg);
  overflow: hidden;
  transition: border-color 0.15s ease;
}
.card-site:hover { border-color: rgba(10, 25, 47, 0.25); }

/* Form controls ------------------------------------------------------------ */
.field {
  width: 100%;
  padding: 0.8125rem 1rem;
  border: 1px solid rgba(10, 25, 47, 0.2);
  border-radius: var(--radius);
  background: #fff;
  font-size: 1rem;
  color: var(--ink);
  transition: border-color 0.15s ease;
}
.field::placeholder { color: #93a8b8; }
.field:hover { border-color: rgba(10, 25, 47, 0.4); }
.field[aria-invalid='true'] { border-color: var(--coral); }

/* Big tappable radio cards for the wizard's choice steps */
.choice {
  display: block;
  position: relative;
  border: 1px solid rgba(10, 25, 47, 0.18);
  border-radius: var(--radius-lg);
  padding: 1.25rem;
  cursor: pointer;
  background: #fff;
  transition: border-color 0.15s ease, background-color 0.15s ease;
}
.choice:hover { border-color: rgba(10, 25, 47, 0.45); }
.choice input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.choice:has(input:checked) {
  border-color: var(--abyss);
  background: #f7fbfc;
  box-shadow: inset 0 0 0 1px var(--abyss);
}
.choice:has(input:focus-visible) {
  outline: 2px solid var(--teal);
  outline-offset: 3px;
}

/* Error text sits with its field and is announced, not just coloured. */
.field-error {
  display: none;
  margin-top: 0.4375rem;
  font-size: 0.8125rem;
  font-weight: 500;
  color: #c93a1f;
}
.field-error.is-shown { display: block; }

/* Wizard step transitions — user-triggered, so motion is welcome here. */
.step { display: none; }
.step.is-active { display: block; animation: step-in 0.28s cubic-bezier(0.16, 1, 0.3, 1) both; }
@keyframes step-in {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 1; transform: none; }
}

/* Progress dots for the wizard */
.step-dot {
  height: 3px;
  flex: 1;
  border-radius: 2px;
  background: rgba(10, 25, 47, 0.12);
  transition: background-color 0.3s ease;
}
.step-dot.is-done { background: var(--teal-ink); }
.step-dot.is-current { background: var(--abyss); }

/* Mobile navigation -------------------------------------------------------- */
.mobile-nav {
  display: none;
  view-transition-name: none;
}
.mobile-nav.is-open { display: block; }

/* Hide anything that needs JS until JS has confirmed it works. */
.no-js-hidden { visibility: hidden; }

/* -----------------------------------------------------------------------------
   9. REDUCED MOTION
   One switch. If someone has asked their system for less movement, they get a
   site with no movement at all — not a slower version of the same thing.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }

  .hero-caustics { display: none; }

  /* Page transitions are motion too. */
  @view-transition { navigation: none; }
}

/* -----------------------------------------------------------------------------
   10. PRINT
   Someone will print the course list on island wifi. Make it survive.
   -------------------------------------------------------------------------- */
@media print {
  .depth-rail,
  .depth-bar,
  .site-header,
  .mobile-nav,
  .btn { display: none !important; }

  body { background: #fff !important; color: #000 !important; }
  .depth-deep, .depth-abyss, .depth-descend { background: #fff !important; }
}
