/* ==========================================================================
   George Farrell PT — small custom stylesheet
   Everything else is handled by Tailwind (loaded via CDN in each page head).
   Only styles that Tailwind utilities can't express live here.

   Palette reference (also set in each page's tailwind.config):
     charcoal-950 #12151a   deepest slate background
     charcoal-900 #181c23   section background
     charcoal-800 #1f242c   cards
     charcoal-700 #2a313b   borders / raised surfaces
     accent       #2fe8a4   mint green
   ========================================================================== */

html {
  scroll-behavior: smooth;
}

body {
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* Consistent focus ring for keyboard users across links, buttons and inputs. */
:focus-visible {
  outline: 2px solid #2fe8a4;
  outline-offset: 3px;
  border-radius: 2px;
}

/* Dark scrollbar so it doesn't break the dark-mode aesthetic (Chrome/Edge). */
::-webkit-scrollbar {
  width: 10px;
}
::-webkit-scrollbar-track {
  background: #12151a;
}
::-webkit-scrollbar-thumb {
  background: #2a313b;
  border-radius: 999px;
}
::-webkit-scrollbar-thumb:hover {
  background: #2fe8a4;
}

/* --------------------------------------------------------------------------
   Scroll reveal
   The hidden state is only applied once JS has added `.reveal-init`, so
   content stays visible if JavaScript is unavailable.
   -------------------------------------------------------------------------- */
[data-reveal].reveal-init {
  opacity: 0;
  transform: translateY(20px);
  transition: opacity 0.6s cubic-bezier(0.16, 1, 0.3, 1),
    transform 0.6s cubic-bezier(0.16, 1, 0.3, 1);
}

[data-reveal].reveal-init.is-visible {
  opacity: 1;
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
  [data-reveal].reveal-init {
    opacity: 1;
    transform: none;
    transition: none;
  }
}

/* --------------------------------------------------------------------------
   Decorative texture: subtle diagonal stripes used behind section headings
   -------------------------------------------------------------------------- */
.bg-stripes {
  background-image: repeating-linear-gradient(
    45deg,
    rgba(255, 255, 255, 0.04) 0px,
    rgba(255, 255, 255, 0.04) 1px,
    transparent 1px,
    transparent 7px
  );
}

/* ==========================================================================
   MEDIA FRAMES
   Every photo/video slot on the site is a `.media-frame` with a fixed shape
   (set by a Tailwind aspect-* class) and a `data-content` key. It holds a
   grey placeholder image until a link is added to assets/js/content-links.js,
   at which point main.js injects the real media as `.frame-media`.

   Because the frame — not the media — owns the dimensions, pasting in a
   Reel, a photo or a YouTube clip can never change the page layout.
   ========================================================================== */

.media-frame {
  position: relative;
  /* Hard clip: anything scaled or offset beyond the frame is cut off. */
  overflow: hidden;
  /* Safari ignores overflow when clipping an iframe inside a rounded box.
     A mask forces it to clip. Both gradient stops are fully opaque, so this
     is a clipping trick only - it doesn't fade the edges. */
  -webkit-mask-image: -webkit-radial-gradient(#fff, #fff);
}

/* Nothing inside a frame is ever allowed to distort. Media fills the frame on
   both axes and the overflow is cropped, so the natural aspect ratio is kept
   whatever shape the frame is. Applies to the grey placeholders and to
   anything main.js injects.

   `object-fit` has no effect on an iframe, so embeds (Instagram, YouTube) are
   fitted by main.js instead — see the Instagram section below. */
.media-frame img,
.media-frame video,
.media-frame iframe {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
}

/* The injected image / video / iframe sits on top of the placeholder. */
.frame-media {
  position: absolute;
  inset: 0;
  border: 0;
  z-index: 1;
}

/* Badges and hover captions sit above the media. */
.frame-layer {
  z-index: 2;
}

/* Chrome that only makes sense on an empty placeholder (play badges, hover
   captions, key labels) is removed once real media has been injected. */
.media-frame.has-media .frame-hide {
  display: none !important;
}

/* --------------------------------------------------------------------------
   Instagram embeds

   An Instagram embed is a fixed-width document laid out as:

       [ username bar ]  ~54px of white chrome
       [     media    ]  a portrait video sits letterboxed inside this box,
                         with black bars down either side
       [ like/comment ]  ~62px of white chrome

   None of it can be styled from here (it's a cross-origin iframe), so the
   only way to show the video and nothing else is to crop. main.js scales the
   iframe up until the video overflows the frame's width, which pushes the
   black side bars outside it, then offsets it vertically so both white bars
   sit beyond the frame's edges where `overflow: hidden` cuts them off.

   How hard it crops is tunable via CONTENT_SETTINGS in
   assets/js/content-links.js.
   -------------------------------------------------------------------------- */
.ig-frame {
  /* Black, so any letterboxing that survives a gentle zoom is invisible. */
  background-color: #000000;
}

.ig-frame > iframe.frame-media {
  /* Anchored top-centre. JS sets width, height and transform inline; the
     transform is scale() followed by translate(-50%, ...), which keeps the
     iframe horizontally centred at any zoom level. */
  top: 0;
  bottom: auto;
  left: 50%;
  right: auto;
  transform-origin: 0 0;
  max-width: none;
}
