/* ── Host page: a splash — one screen, nothing to scroll (resource CSS below is untouched) ── */
html, body {
  margin: 0;
  padding: 0;
  height: 100%;
  /* `clip` makes no scroll container at all, so nothing can scroll the page — not a
     gesture, not a key, not script. `hidden` is the fallback for browsers without
     it, and stops the user scrolling just the same. Both matter while the image
     window is open: the carousel is scaled to 1.2 behind it and spills past the
     viewport, which `hidden` alone would leave as a scrollable 84px. */
  overflow: hidden;
  overflow: clip;
  overscroll-behavior: none;  /* no pull-to-refresh, no scroll chaining */
}

body {
  font-family: Haffer, Arial, sans-serif;
  background-color: #fff;
}

/* ─────────────────── Osmo Supply — Liquid Glass Carousel (1:1) ─────────────────── */
.glass-carousel {
  background-color: #fff;
  justify-content: center;
  align-items: center;
  min-height: 100svh;
  display: flex;
  position: relative;
  overflow: clip;
}

.glass-carousel__canvas {
  width: 100%;
  height: 100%;
  display: block;
  position: absolute;
  inset: 0%;
  touch-action: pan-y;
  user-select: none;  
  -webkit-user-select: none;
  -webkit-touch-callout: none;
  -webkit-tap-highlight-color: transparent;      
}

[data-glass-carousel-wheel="all"] canvas {
  touch-action: none;
}
  
[data-glass-carousel-pointer="grab"] canvas {
  cursor: grab;
}
  
[data-glass-carousel-pointer="grabbing"] canvas {
  cursor: grabbing;
}

.glass-carousel__list {
  scroll-snap-type: x mandatory;
  justify-content: flex-start;
  align-items: center;
  padding-left: 2em;
  padding-right: 2em;
  display: flex;
  position: absolute;
  inset: 0%;
  overflow-x: auto;
}

/* Once the canvas takes over, the list stays for screen readers only */
[data-glass-carousel="canvas"] [data-glass-carousel-list] {
  width: 1px;
  height: 1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.glass-carousel__item {
  scroll-snap-align: center;
  flex: none;
  height: 35%;
}

[data-glass-carousel-item] [data-glass-carousel-content] {
  visibility: hidden;
}

.glass-carousel__item-img {
  object-fit: cover;
  height: 100%;
  display: block;
}

.glass-carousel__item-p {
  margin-top: 0;
  margin-bottom: 0;
  font-family: Haffer, Arial, sans-serif;
  font-size: 1em;
  font-weight: 400;
  line-height: 1.2;
}

.glass-carousel__item-p.is--faded {
  opacity: .6;
}

.glass-carousel__caption {
  pointer-events: none;
  text-align: center;
  padding-left: 1em;
  padding-right: 1em;
  position: absolute;
  top: 15%;
  left: 50%;
  transform: translate(-50%);
}

.glass-carousel__counter {
  pointer-events: none;
  text-align: center;
  background-color: #0000000f;
  border-radius: .25em;
  min-width: 5em;
  padding: .625em 1em;
  font-size: 1em;
  position: absolute;
  bottom: 15%;
  left: 50%;
  transform: translate(-50%);
}

/* ───────── Osmo Supply — Masked Window Page Transition (1:1) ───────── */
.transition {
  z-index: 100;
  pointer-events: none;
  position: fixed;
  inset: 0;
  overflow: clip;
}

.transition__dark {
  opacity: 0;
  background-color: #000;
  width: 100%;
  height: 100%;
  position: absolute;
  top: 0;
  left: 0;
}

/* ───────── The window that transition opens (host styling) ───────── */
/* The counter is not shown. It stays in the page because the intro tour and the
   interaction lock both read which image is centred out of its text — the carousel
   keeps writing to it either way. This rule sits after the resource's own
   .glass-carousel__counter, which would otherwise win back its box. */
.glass-carousel__counter {
  display: none;
}


.image-window {
  visibility: hidden;
  background-color: #0b0b0c;
  position: fixed;
  inset: 0;
}

.image-window:focus {
  outline: none;
}

/* The picture fills the whole screen — the caption and the button sit over it,
   on a scrim so they stay readable against whatever the image is doing. */
.image-window__figure {
  margin: 0;
  position: absolute;
  inset: 0;
  /* js/image-window.js paints the row's already-decoded copy of the same photograph
     here, so the window never opens onto an empty rectangle while the full-size file
     is still on the wire. Same crop, same framing — only the sharpness changes when
     the real one lands on top. */
  background-position: center;
  background-size: cover;
}

.image-window__img {
  object-fit: cover;
  object-position: center;
  width: 100%;
  height: 100%;
  display: block;
  position: absolute;
  inset: 0;
}




/* The wordmark is set as live text — letterspaced caps in the page's own stack —
   rather than an image of the logo, so it stays sharp at any size and is real,
   selectable, translatable text to a screen reader. */
.image-window__masthead {
  text-align: center;
  color: #fff;
  width: min(92vw, 62rem);
  position: absolute;
  top: 50%;
  left: 50%;
  opacity: 0;
  transform: translate(-50%, -50%);
  /* The page itself cannot scroll — that is the whole point of a splash — but at 400%
     browser zoom the viewport is 320x256 CSS pixels and the stack simply does not fit
     in it: Beta Login sat 58px below the bottom edge with no way to reach it, which
     fails WCAG 1.4.10. So the writing, and only the writing, may scroll, and only when
     it has run out of room. On every ordinary screen there is slack here and this
     changes nothing. The row is long gone by the time this is on screen, so there is
     still nowhere to scroll back to. */
  max-height: calc(100% - 5.5rem);
  overflow-y: auto;
  overscroll-behavior: contain;
}

.image-window__wordmark {
  pointer-events: none;
  margin: 0;
  font-family: Haffer, Arial, sans-serif;
  font-size: clamp(2.75rem, 11vw, 9.5rem);
  font-weight: 700;
  line-height: 1;
  letter-spacing: .22em;
  text-indent: .22em;   /* letter-spacing trails the last letter — put it back to centre */
  text-transform: uppercase;
  text-shadow: 0 2px 44px #00000066;
}

/* Family, size, weight and .6 opacity are the frame captions' exactly. Two things
   are not: the leading is opened up, because a sentence over two lines needs more
   than the 1.2 a single line wanted; and the shadow is heavier, because the scrim
   those captions sat on has gone with them. The measure is capped and balanced so
   it breaks into two even lines under the mark rather than one long one. */
.image-window__line {
  pointer-events: none;
  margin: 2.25em auto 0;
  max-width: 68ch;
  font-family: Haffer, Arial, sans-serif;
  font-size: 1em;
  font-weight: 400;
  line-height: 1.55;
  opacity: .72;
  /* `pretty` rather than `balance`: this is a paragraph now, and balancing is meant
     for a line or two — it only has to keep the last line off a single word. */
  text-wrap: pretty;
  text-shadow: 0 1px 20px #000000a6, 0 1px 3px #0000005c;
}


[data-image-window].is--settled .image-window__masthead {
  animation: masthead-arrive 1s cubic-bezier(.22, .61, .36, 1) both;
}

@keyframes masthead-arrive {
  from { opacity: 0; transform: translate(-50%, -46%); }
  to   { opacity: 1; transform: translate(-50%, -50%); }
}

/* Veni. Indagavi. Vici. — set the way the wordmark is, just small and far apart:
   uppercase, heavy, widely tracked, and carrying the same text-indent so the
   trailing letter-space does not pull it off centre. */
/* Veni. Indagavi. Vici. — set the way the wordmark is, just small and far apart:
   uppercase, heavy, and tracked. The tracking is not a fixed value here though; it is
   measured and set by js/motto-fit.js so the line spans the full width of the screen
   at any size. Left-aligned, not centred: letter-spacing trails the final letter, and
   centring would push the run half a space off the edge it is meant to touch. */
.image-window__motto {
  pointer-events: none;
  text-align: left;
  color: #fff;
  margin: 0;
  padding-inline: clamp(1.25rem, 3.4vw, 3rem);
  font-family: Haffer, Arial, sans-serif;
  font-size: clamp(1rem, 1.25vw, 1.25rem);
  font-weight: 600;
  line-height: 1;
  /* Both of these are placeholders — js/motto-fit.js measures and replaces them so the
     line spans whatever width it is given. They are only what shows if that never
     runs. */
  letter-spacing: .4em;
  word-spacing: 1em;
  text-transform: uppercase;
  text-shadow: 0 1px 20px #000000b3;
  white-space: nowrap;
  position: absolute;
  bottom: 2.75em;
  left: 0;
  right: 0;
  opacity: 0;
}

[data-image-window].is--settled .image-window__motto {
  animation: motto-arrive 1s cubic-bezier(.22, .61, .36, 1) .3s both;
}

@keyframes motto-arrive {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: .58; transform: translateY(0); }
}

/* ─────────── Osmo Supply — Interactive Dots Grid (Background) (1:1) ─────────── */
.interactive-dots-grid {
  pointer-events: none;
  width: 100%;
  height: 100%;
  position: absolute;
  top: 0;
  left: 0;
}

/* The grid is only in the layout once the window has finished opening. Two reasons:
   it measures itself from the element's box, which is still being scaled during the
   transition; and while it is display:none its observers report it as neither sized
   nor intersecting, so the resource never starts its render loop — no full-screen
   canvas redrawing every frame behind the splash. */
.interactive-dots-grid {
  display: none;
}

[data-image-window].is--settled .interactive-dots-grid {
  display: block;
  animation: dots-arrive .8s cubic-bezier(.22, .61, .36, 1) both;

  /* The grid runs at full strength across the photograph but steps back to about a
     fifth of it behind the paragraph, so the dots stop crossing the letters. The
     ellipse is measured onto the paragraph by js/dots-clearing.js; the fallbacks here
     are a sane centre band for the moment before it runs, and for a browser without
     custom properties. A mask, not an opacity — the dots still light up under the
     cursor in there, just quietly, and the photograph underneath is untouched. */
  -webkit-mask-image: radial-gradient(ellipse var(--clear-rx, 30%) var(--clear-ry, 12%)
    at var(--clear-x, 50%) var(--clear-y, 47%),
    #00000038 0%, #00000038 58%, #000 100%);
          mask-image: radial-gradient(ellipse var(--clear-rx, 30%) var(--clear-ry, 12%)
    at var(--clear-x, 50%) var(--clear-y, 47%),
    #00000038 0%, #00000038 58%, #000 100%);
}

@keyframes dots-arrive {
  from { opacity: 0; }
  to { opacity: 1; }
}

/* The one action on the page, in the shape the nav's selected tab used to have. */
.beta-login {
  display: inline-block;
  text-decoration: none;
  margin-top: 6em;
  padding: .65em 1.35em;
  font-family: Haffer, Arial, sans-serif;
  font-size: 1em;
  line-height: 1.2;
  color: #16120e;
  cursor: pointer;
  pointer-events: auto;
  background-color: #fff;
  border: 0;
  border-radius: 100em;
  transition: background-color .25s ease;
}

.beta-login:hover {
  background-color: #ffe2c6;
}

/* Same as the copy button: the masthead fades in around the middle of the screen and
   can land under a pointer that has not moved, and this one tinted white → peach →
   white again on arrival, which is a blink in the plainest sense. Held back until
   there is a hand on the mouse — see js/pointer-intent.js. */
html:not([data-pointer-moved]) .beta-login:hover {
  background-color: #fff;
}

/* The user-agent focus ring computed to near-black, which on a dark photograph is no
   ring at all. */
.beta-login:focus-visible {
  outline: 2px solid #fff;
  outline-offset: 3px;
}

/* ──────────── Osmo Supply — Copy Email to Clipboard Button (1:1) ──────────── */
.copy-email-wrapper {
  grid-column-gap: 2em;
  grid-row-gap: 2em;
  flex-flow: column;
  justify-content: center;
  align-items: center;
  display: flex;
}

.copy-email-eyebrow {
  opacity: .5;
  text-align: center;
  margin-bottom: 0;
  font-size: 1em;
  line-height: 1;
}

.copy-email-button {
  grid-column-gap: .75em;
  grid-row-gap: .75em;
  background-color: #fff;
  border-radius: .5em;
  justify-content: flex-start;
  align-items: center;
  padding: .75em 1em .75em .75em;
  display: flex;
}

.copy-email-button:focus {
  outline-offset: 0px;
  border: 1px #000;
  outline: 3px #131313;
}

.copy-email-button:focus-visible, .copy-email-button[data-wf-focus-visible] {
  outline-offset: 4px;
  border-style: none;
  outline: 2px solid #fff;
}

.copy-email-text__wrap {
  flex-flow: column;
  justify-content: flex-start;
  align-items: center;
  height: 1.2em;
  font-size: 2em;
  line-height: 1.2;
  display: flex;
  overflow: hidden;
}

.copy-email-text__el {
  white-space: nowrap;
  font-size: 1em;
  transition: transform .45s cubic-bezier(.65, 0, 0, 1);
}

.copy-email-icon__wrap {
  color: #fff;
  background-color: #22502e;
  border-radius: .375em;
  justify-content: center;
  align-items: center;
  width: 2.5em;
  height: 2.5em;
  padding: .5em;
  transition: background-color .2s;
  display: flex;
}

/* Hover styling */
@media (hover: hover) {
  .copy-email-button:hover .copy-email-icon__wrap{
    background: rgba(34, 80, 46, 0.9);
  }
  .copy-email-button:hover .copy-email-text__el{
    transform: translate(0px, -100%);
  }
}

/* Keyboard focus styling */
.copy-email-button:focus .copy-email-icon__wrap{
  background: rgba(34, 80, 46, 0.9);
}
.copy-email-button:focus .copy-email-text__el {
  transform: translate(0px, -100%);
}

/* 'Copied' state, when a user has clicked the button */
[data-copy-button="copied"] .copy-email-icon__wrap{ background: #0F8E2E !important; }
[data-copy-button="copied"] .copy-email-text__el{ transform: translate(0px, -200%) !important; }

@media screen and (max-width: 479px) {
  .copy-email-text__wrap {
    font-size: 1em;
  }
}

/* ── The button in its own context (host styling; the resource is a white card, and
      this sits on a photograph). The icon square and eyebrow are not used, so those
      rules above simply match nothing — which is how the resource ships. ── */
.image-window .copy-email-wrapper {
  pointer-events: auto;
  /* Everything in the resource is sized in em off this one value, so the whole
     control scales from here rather than from a dozen overrides. */
  font-size: .58rem;
  gap: 1.6em;
  margin-top: 5em;
}

/* The glass the window's other furniture is made of, not a solid white card. */
.image-window .copy-email-button {
  cursor: pointer;
  color: #fff;
  font-family: Haffer, Arial, sans-serif;
  background-color: #ffffff1f;
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
  border: 0;
  border-radius: 100em;
  padding: .62em 1.7em;
}

.image-window .copy-email-button:hover {
  background-color: #ffffff2e;
}

/* Hover, but only once there is a hand on the mouse — see js/pointer-intent.js. The
   resource's own rule is left exactly as it ships; this simply outranks it until the
   pointer has moved at least once. */
html:not([data-pointer-moved]) .image-window .copy-email-button:hover .copy-email-text__el {
  transform: none;
}

html:not([data-pointer-moved]) .image-window .copy-email-button:hover {
  background-color: #ffffff1f;
}

.image-window .copy-email-text__wrap {
  font-size: 1.9em;
}

/* ─────────────── Short viewports (a phone on its side, a squat window) ───────────────
   Everything above sizes off the *width*, which is right until the width is the long
   edge: at 844x390 the wordmark asked for 11vw = 93px and the stack ran off the screen
   at both ends. The page cannot scroll, so on a short viewport the whole composition
   has to come down together rather than any one part of it. */
@media (max-height: 560px) {
  .image-window__wordmark {
    font-size: clamp(1.5rem, 8.5vh, 3.5rem);
  }

  .image-window__line {
    max-width: min(96ch, 92vw);
    margin-top: 1.15em;
    font-size: .8125rem;
    line-height: 1.45;
  }

  .image-window .copy-email-wrapper {
    margin-top: 2.2em;
    font-size: .5rem;
  }

  .beta-login {
    margin-top: 1.7em;
    font-size: .8125rem;
    padding: .5em 1em;
  }

  .image-window__motto {
    bottom: 1rem;
    font-size: .6875rem;
  }
}

/* ─────────────── Narrow viewports (phones held upright) ─────────────── */
@media (max-width: 30em) {
  .beta-login {
    margin-top: 4em;
    font-size: .875rem;
  }

  /* The motto is set to span the screen, and the tracking needed to do that is worked
     out from whatever the type already is. At 16px — which is what the rule above came
     to on every phone, the viewport term being far too small to reach the floor — the
     line came out small and pulled thin, nearly half an em of air between the letters.
     Bigger type needs less of that air to reach the same edges: at 390px this takes the
     tracking from .47em to about .24em, so the line reads as a line and still spans the
     width. Held to min-height so a phone on its side keeps the short-viewport size. */
  .image-window__motto {
    font-size: clamp(1.125rem, 5.4vw, 1.5rem);
  }
}

@media (max-width: 30em) and (max-height: 560px) {
  .image-window__motto {
    font-size: .6875rem;
  }
}

/* ─────────────── Between short and roomy ───────────────
   The block above catches a viewport 560px tall or less. Over that the full-size stack
   came back all at once, and between about 560 and 680 there is not yet the room for
   it: at 320x568 — an iPhone SE, and any desktop window dragged to that height — the
   Beta Login button landed on top of the motto, and it did so at every width from 280
   to 540. Measured, the clearance fell from 80px at 560 tall to below zero at 568 and
   did not recover until 680. This is that cliff, sized between the two blocks.
   It must stay after the narrow-viewport rule above, which sets its own button margin
   and would otherwise push the button further down rather than less. */
@media (min-height: 561px) and (max-height: 680px) {
  .image-window__wordmark {
    font-size: clamp(2rem, 9.5vw, 4.5rem);
  }

  .image-window__line {
    margin-top: 1.7em;
    font-size: .875rem;
    line-height: 1.5;
  }

  .image-window .copy-email-wrapper {
    margin-top: 3.4em;
  }

  .beta-login {
    margin-top: 2.8em;
  }

  .image-window__motto {
    bottom: 1.75em;
  }
}


/* ─────────────── The caption, when the row runs vertically ───────────────
   Horizontally the panels are a band across the middle and the caption sits clear
   above them. Vertically they fill the height, so the caption is guaranteed to have a
   photograph pass behind it — and it is dark text. It gets the page's own white as a
   surface to sit on, which reads as the section showing through rather than a card. */
[data-glass-axis="vertical"] .glass-carousel__caption {
  background-color: #ffffffe0;
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
  border-radius: 100em;
  padding: .7em 1.5em;
}
