/* ==========================================================================
   FAMILY TREE DENTAL — office.css
   The Our Office page's own three sections, and nothing else.
   ---------------------------------------------------------------------------
   Loaded after style.css and system.css. Everything shared — tokens, the nav
   pill, buttons, the eyebrow, the headline mask, the appointment band, the
   testimonial split, the clinic panel, the wave — is already supplied by those
   two and by the global components. What is here is only:

     01. The hero        the green panel and the film beside it
     02. The play button
     03. The introduction
     04. The gallery     an editorial arrangement, not a uniform grid
     05. Entry states    this page's own reveal channels
     06. Responsive
     07. Reduced motion

   Entry states are authored in CSS and lifted by `.no-js` — the same contract
   system.css section 04 uses, so a page that never gets its JavaScript is a
   finished page rather than an empty one.
   ========================================================================== */


/* ==========================================================================
   01. THE HERO
   ---------------------------------------------------------------------------
   TWO PANELS, EQUAL HEIGHT, NO GAP. The design puts a green field and a film
   side by side and lets them meet in the middle; a gap between them would
   turn one band into two cards. The band is full-bleed and sits under the
   pill, so its top padding has to clear the whole of the chrome.
   ========================================================================== */
.of-hero {
  position: relative;
  isolation: isolate;
  overflow: clip;
  padding-top: calc(var(--util-h) + var(--nav-h) + var(--hero-inset) + var(--hero-pad));
  background: var(--sv-ivory);
}

.of-hero__inner {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.06fr);
  align-items: stretch;
  /* THE BAND'S HEIGHT IS SET HERE AND NOWHERE ELSE. The <video> is taken out
     of flow below so it cannot contribute its intrinsic height — a portrait
     clip would otherwise stretch this band past the fold and push the title
     with it. The row is as tall as this says, and the film crops to fit. */
  min-height: clamp(22rem, 48vh, 31rem);
}

/* --- The green field ----------------------------------------------------- */
.of-hero__panel {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  display: flex;
  align-items: center;
  padding: clamp(2rem, 5vw, 4.5rem) clamp(1.25rem, 5vw, 5rem);
  /* The practice's green, deepened towards the outside edge so the type has
     a darker ground to sit on than the middle of the panel. */
  background:
    radial-gradient(120% 90% at 84% 12%, rgba(127, 227, 212, .2) 0%, rgba(127, 227, 212, 0) 62%),
    linear-gradient(152deg, #5aad38 0%, #4c9c2e 46%, #3d7f25 100%);
}

/* A single very soft grain wash. Flat colour across a panel this large reads
   as a swatch; this gives it a surface without giving it a pattern. */
.of-hero__grain {
  position: absolute;
  inset: -20%;
  z-index: -1;
  background:
    radial-gradient(38% 34% at 22% 28%, rgba(255, 255, 255, .14) 0%, rgba(255, 255, 255, 0) 70%),
    radial-gradient(30% 40% at 78% 76%, rgba(6, 33, 58, .16) 0%, rgba(6, 33, 58, 0) 72%);
  pointer-events: none;
}

/* The practice's own mark, huge and nearly invisible, drifting on the
   pointer. Same device the footer uses, so the two ends of the page rhyme. */
.of-hero__leaf {
  position: absolute;
  right: -6%;
  bottom: -34%;
  z-index: -1;
  width: min(30vw, 22rem);
  color: rgba(255, 255, 255, .085);
  pointer-events: none;
}
.of-hero__leaf svg { width: 100%; height: auto; }

.of-hero__copy {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: 30rem;
  margin-left: auto;
  padding-right: clamp(0rem, 2vw, 2rem);
}

/* On the green, the breadcrumb's ink has to invert. */
.sv-crumbs--light ol,
.sv-crumbs--light li { color: rgba(255, 255, 255, .72); }
.sv-crumbs--light a { color: rgba(255, 255, 255, .82); }
.sv-crumbs--light a:hover { color: #fff; }
.sv-crumbs--light [aria-current="page"] { color: #fff; }

.of-hero__title {
  margin-top: clamp(.9rem, 2.5vh, 1.5rem);
  font-family: var(--f-display);
  font-size: clamp(2.6rem, 1rem + 5.6vw, 4.6rem);
  font-weight: 400;
  line-height: 1.02;
  letter-spacing: -0.022em;
  color: #fff;
}
/* The accent word is white too — a second colour on a green field is one
   colour too many. It carries the italic and nothing else. */
.of-hero__title em { font-style: italic; color: rgba(255, 255, 255, .93); }

.of-hero__tag {
  margin-top: clamp(.6rem, 1.6vh, 1rem);
  font-family: var(--f-display);
  font-style: italic;
  font-size: clamp(1rem, .9rem + .45vw, 1.28rem);
  color: rgba(255, 255, 255, .88);
}

/* --- The film ------------------------------------------------------------ */
.of-hero__stage { position: relative; }

.of-hero__frame {
  position: relative;
  margin: 0;
  height: 100%;
  overflow: hidden;
  background: #06213a;
}
/* ABSOLUTE, so the clip's own dimensions never drive the band's height —
   see the note on .of-hero__inner. The frame is sized by the grid row and
   the film covers whatever that turns out to be. */
.of-hero__video {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  will-change: transform;
}


/* ==========================================================================
   02. THE PLAY BUTTON
   ---------------------------------------------------------------------------
   Authored `hidden` and revealed by office.js, which removes the video's own
   `controls` in the same breath. So the native controls are what a visitor
   without JavaScript gets — a working video either way, never a decorative
   button that does nothing.
   ========================================================================== */
.of-play {
  position: absolute;
  top: 50%; left: 50%;
  z-index: 2;
  display: grid;
  place-items: center;
  width: clamp(4.5rem, 8vw, 6rem);
  aspect-ratio: 1;
  padding: 0;
  color: #fff;
  /* Dark rather than light. A white scrim disappears against the bright
     ceiling and lit walls this clip is full of; a dark one holds the white
     glyph at every frame of the footage. */
  background: rgba(6, 33, 58, .42);
  border: 0;
  border-radius: 50%;
  cursor: pointer;
  box-shadow: 0 10px 30px rgba(6, 33, 58, .3);
  -webkit-backdrop-filter: blur(8px) saturate(140%);
  backdrop-filter: blur(8px) saturate(140%);
  transform: translate(-50%, -50%);
  transition: background var(--t-fast) var(--ease-out),
              transform var(--t-med) var(--ease-out);
}
.of-play:hover { background: rgba(6, 33, 58, .56); transform: translate(-50%, -50%) scale(1.05); }
.of-play:focus-visible { outline: 2px solid #fff; outline-offset: 4px; }

/* The ring breathes only while the film is paused — once it is playing the
   button is a pause control and a pulsing pause control is a distraction. */
.of-play__ring {
  position: absolute;
  inset: -6px;
  border: 1px solid rgba(255, 255, 255, .5);
  border-radius: 50%;
  animation: of-pulse 3.4s var(--ease-out) infinite;
}
@keyframes of-pulse {
  0%, 100% { transform: scale(1);    opacity: .55; }
  50%      { transform: scale(1.09); opacity: .18; }
}

/* One element, two glyphs. A triangle drawn with borders becomes two bars by
   swapping the border for a box-shadow — no icon swap, no second element. */
.of-play__mark {
  width: 0; height: 0;
  margin-left: .28em;
  border-top: .58rem solid transparent;
  border-bottom: .58rem solid transparent;
  border-left: .95rem solid currentColor;
  transition: border-color var(--t-fast) var(--ease-out);
}
.of-play[aria-pressed="true"] .of-play__ring { animation: none; opacity: .3; }
.of-play[aria-pressed="true"] .of-play__mark {
  width: .28rem; height: 1.1rem;
  margin-left: 0;
  border: 0;
  background: currentColor;
  box-shadow: .48rem 0 0 currentColor;
  transform: translateX(-.24rem);
}

/* Present for a reader, absent for a viewer — the button is a circle. */
.of-play__label {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}


/* ==========================================================================
   03. THE INTRODUCTION
   ---------------------------------------------------------------------------
   One measured column in a lot of air. The design centres it, and centred is
   right for three short paragraphs — but the measure is held to ~62ch so the
   lines never become the long centred ribbons that make a page hard to read.
   ========================================================================== */
.of-intro {
  position: relative;
  isolation: isolate;
  overflow: clip;
  padding-block: clamp(4rem, 11vh, 8rem) clamp(2.5rem, 7vh, 5rem);
  background: linear-gradient(180deg, var(--sv-ivory) 0%, #f4f9ff 58%, #eef5fd 100%);
  text-align: center;
}

.of-intro__wash {
  position: absolute;
  top: -30%;
  left: 50%;
  z-index: -1;
  width: min(70vw, 52rem);
  aspect-ratio: 1;
  border-radius: 50%;
  background: radial-gradient(circle at 50% 50%,
              rgba(127, 227, 212, .2) 0%,
              rgba(110, 178, 244, .13) 45%,
              rgba(110, 178, 244, 0) 70%);
  filter: blur(20px);
  transform: translateX(-50%);
  pointer-events: none;
}

.of-intro__inner {
  width: min(56rem, 100% - 2 * var(--gutter));
  margin-inline: auto;
}
.of-intro .sv-eyebrow { justify-content: center; }

.of-intro__title {
  margin-top: clamp(.8rem, 2vh, 1.2rem);
  font-family: var(--f-display);
  font-size: clamp(2rem, 1.05rem + 3vw, 3.5rem);
  font-weight: 400;
  line-height: 1.08;
  letter-spacing: -0.018em;
  color: var(--c-ink);
}

.of-intro__prose { margin-top: clamp(1.3rem, 3.5vh, 2.2rem); }

.of-intro__lede {
  max-width: 60ch;
  margin-inline: auto;
  font-size: clamp(1.05rem, .98rem + .3vw, 1.22rem);
  line-height: 1.72;
  color: rgba(11, 45, 82, .8);
}

.of-intro__p {
  max-width: 62ch;
  margin: clamp(1rem, 2.4vh, 1.5rem) auto 0;
  font-size: clamp(.98rem, .95rem + .16vw, 1.06rem);
  line-height: 1.78;
  color: rgba(11, 45, 82, .72);
}

/* The one link in the prose. Underlined from the start — a link inside a
   paragraph that only reveals itself on hover is a link most people never
   find. */
.of-intro__link {
  color: var(--c-blue-700);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: .18em;
  text-decoration-color: rgba(26, 114, 214, .4);
  transition: text-decoration-color var(--t-fast) var(--ease-out),
              color var(--t-fast) var(--ease-out);
}
.of-intro__link:hover { color: var(--c-blue-900, #0b3b56); text-decoration-color: currentColor; }


/* ==========================================================================
   04. THE GALLERY
   ---------------------------------------------------------------------------
   NOT A UNIFORM GRID. Six columns, and each photograph claims a different
   number of them, so the eye moves through the set instead of scanning a
   table. Two pictures carry the composition: the exterior opens it wide, and
   the corridor — the only tall photograph in the set — runs down beside the
   two small ones.

   The spans are authored against SIX columns rather than three so a sixth
   photograph can be given a half-column offset later without the whole grid
   being re-authored.
   ========================================================================== */
.of-gal {
  position: relative;
  padding-block: clamp(2.5rem, 7vh, 5rem) clamp(4rem, 11vh, 8rem);
  background: linear-gradient(180deg, #eef5fd 0%, var(--sv-ivory) 46%);
}

.of-gal__grid {
  width: var(--sv-shell);
  margin-inline: auto;
  padding: 0;
  list-style: none;
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: clamp(.75rem, 1.6vw, 1.35rem);
}

/* Two of six columns is the default and the small photographs never get more.
   THE TOP ROW'S HEIGHT IS SET BY ONE ELEMENT — the wide cell's aspect ratio —
   and everything beside it stretches to match. Only the two high-resolution
   photographs are ever asked to fill that height. */
.of-gal__cell { grid-column: span 2; }
/* The opener: the street elevation, four columns, shot 4:3. */
.of-gal__cell--wide { grid-column: span 4; }
/* The corridor — the only portrait in the set. Two columns beside the
   opener, where its 3:4 original is close to the shape of the slot and it is
   barely cropped at all. */
.of-gal__cell--tall { grid-column: span 2; }

.of-gal__frame {
  position: relative;
  margin: 0;
  height: 100%;
  overflow: hidden;
  border-radius: var(--sv-r-md);
  background: var(--sv-ice);
  box-shadow: 0 10px 26px rgba(11, 45, 82, .1);
}
/* The one authored ratio. It decides the top row, and the corridor beside it
   simply fills what is left. */
.of-gal__cell--wide .of-gal__frame { aspect-ratio: 16 / 10; height: auto; }
/* The lower row: three equal frames at a size their originals can carry. */
.of-gal__cell:not(.of-gal__cell--wide):not(.of-gal__cell--tall) .of-gal__frame {
  aspect-ratio: 4 / 3;
  height: auto;
}

.of-gal__photo {
  width: 100%; height: 100%;
  object-fit: cover;
  /* Slightly oversized at rest so the hover scale has somewhere to go
     without the edges of the frame ever showing through. */
  transition: transform 1.05s var(--ease-out);
  will-change: transform;
}
.of-gal__frame:hover .of-gal__photo { transform: scale(1.045); }

.of-gal__veil {
  position: absolute;
  inset: 0;
  background: linear-gradient(200deg, rgba(6, 33, 58, 0) 52%, rgba(6, 33, 58, .26) 100%);
  opacity: 0;
  transition: opacity var(--t-med) var(--ease-out);
  pointer-events: none;
}
.of-gal__frame:hover .of-gal__veil { opacity: 1; }


/* ==========================================================================
   05. ENTRY STATES — this page's own reveal channels
   ========================================================================== */
[data-of-mask] { clip-path: inset(0% 0% 100% 0%); }
[data-of-tile] { clip-path: inset(0% 0% 100% 0%); }

.no-js [data-of-mask],
.no-js [data-of-tile] { clip-path: none; }


/* ==========================================================================
   06. RESPONSIVE
   ========================================================================== */
@media (max-width: 1180px) {
  .of-hero__inner { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  .of-hero__copy  { max-width: 26rem; }
}

/* The band becomes a stack: the green field, then the film under it. */
@media (max-width: 980px) {
  .of-hero__inner { grid-template-columns: minmax(0, 1fr); min-height: 0; }
  .of-hero__copy  { max-width: none; margin-left: 0; padding-right: 0; }
  .of-hero__panel { padding-block: clamp(2.25rem, 7vw, 3.5rem); }
  .of-hero__frame { aspect-ratio: 16 / 10; height: auto; }
  .of-hero__leaf  { right: -12%; bottom: -40%; width: min(46vw, 18rem); }

  /* Four columns: the opener runs full width, everything else pairs up. */
  .of-gal__grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .of-gal__cell,
  .of-gal__cell--tall { grid-column: span 2; }
  .of-gal__cell--wide { grid-column: span 4; }
  /* The corridor is no longer beside the opener, so it needs its own ratio
     rather than a neighbour's height to fill. */
  .of-gal__cell--tall .of-gal__frame { aspect-ratio: 4 / 3; height: auto; }
}

@media (max-width: 560px) {
  .of-hero__title { font-size: clamp(2.4rem, 1rem + 9vw, 3.4rem); }
  .of-intro       { padding-block: clamp(3rem, 8vh, 4.5rem) clamp(2rem, 5vh, 3rem); }
  .of-intro__lede { text-align: left; }
  .of-intro__p    { text-align: left; }

  /* Two across at this width would make each photograph a thumbnail. One
     column, full width, is the only honest way to show a room on a phone. */
  .of-gal__grid { grid-template-columns: minmax(0, 1fr); }
  .of-gal__cell,
  .of-gal__cell--wide,
  .of-gal__cell--tall { grid-column: span 1; }
  .of-gal__frame,
  .of-gal__cell--wide .of-gal__frame,
  .of-gal__cell--tall .of-gal__frame { aspect-ratio: 4 / 3; height: auto; }
}

@media (max-width: 400px) {
  .of-play { width: 4rem; }
}


/* ==========================================================================
   07. REDUCED MOTION
   ---------------------------------------------------------------------------
   office.js returns before building a timeline when the query matches, so
   what is left here is the motion it does not own: the hover crops, the veil
   and the play button's pulse.
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  [data-of-mask],
  [data-of-tile] { clip-path: none; }

  .of-play__ring { animation: none; }
  .of-gal__photo,
  .of-gal__veil { transition: none; }
  .of-gal__frame:hover .of-gal__photo { transform: none; }
  .of-hero__video,
  .of-gal__photo { will-change: auto; }
}
