/* OMFC International | components.css: header, buttons, cursor, loader, menu,
   hold-to-install button and photo viewer. */


/* === 1. Site header ===================================================== */

/* Fixed bar [empty | bar | button]; clicks pass through the header except on its children */
.site-header {
  position: fixed;
  z-index: var(--z-header);
  top: var(--header-top);
  left: var(--margin);
  right: var(--margin);
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: var(--s-4);
  color: var(--bone);
  pointer-events: none;
  transition: color var(--dur-3) var(--ease-out);
}

.site-header > * {
  pointer-events: auto;
}

/* Set by initHeader() in ui.js when a light section is under the header */
.site-header.is-on-light {
  color: var(--ink);
}

/* The dark centre bar: wordmark | clock | menu */
.site-header__bar {
  grid-column: 2;
  display: flex;
  align-items: stretch;
  height: var(--header-h);
  background: var(--graphite);
  color: var(--bone);
  box-shadow: inset 0 0 0 1px rgba(245, 243, 238, 0.07);
}

.site-header__cta {
  grid-column: 3;
  justify-self: end;
}

/* Wordmark (stands in for the logo) ------------------------------------------ */

.wordmark {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0 1rem 0 0.95rem;
  line-height: 1;
}

.wordmark__mark {
  font-family: var(--font-sans);
  font-size: 1.02rem;
  font-weight: 780;
  font-stretch: 122%;
  letter-spacing: 0.02em;
}

.wordmark__sub {
  font-family: var(--font-mono);
  font-size: 0.5625rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  opacity: 0.55;
}

/* Clock ---------------------------------------------------------------------- */

.clock {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  padding: 0 1rem;
  border-inline: 1px solid rgba(245, 243, 238, 0.1);
  font-family: var(--font-mono);
  font-size: var(--fs-label);
  font-weight: 500;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  white-space: nowrap;
}

/* Blinking hi-vis square, like a site status light */
.clock__dot {
  width: 6px;
  height: 6px;
  background: var(--hivis);
  animation: clock-blink 2s steps(1, end) infinite;
}

.clock__city {
  opacity: 0.55;
}

/* Tabular figures stop the digits from jiggling as they change */
.clock__time {
  min-width: 8ch;
  font-variant-numeric: tabular-nums;
}

.clock__tz {
  opacity: 0.55;
}

@keyframes clock-blink {
  50% {
    opacity: 0.15;
  }
}

/* Menu button ---------------------------------------------------------------- */

.menu-toggle {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  padding: 0 0.95rem;
  font-family: var(--font-mono);
  font-size: var(--fs-label);
  font-weight: 500;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  transition:
    background-color var(--dur-2) var(--ease-out),
    color var(--dur-2) var(--ease-out);
}

.menu-toggle:hover {
  background: var(--hivis);
  color: var(--ink);
}

/* Label roll: a copy of the word (data-text) waits below and rolls up on hover */
.menu-toggle__label {
  display: block;
  height: 1.4em;
  overflow: hidden;
  line-height: 1.4;
}

.menu-toggle__label > span {
  position: relative;
  display: block;
  transition: transform 0.5s var(--ease-roll);
}

.menu-toggle__label > span::after {
  content: attr(data-text);
  position: absolute;
  top: 100%;
  left: 0;
}

.menu-toggle:hover .menu-toggle__label > span {
  transform: translateY(-100%);
}

/* Two-line icon that turns into a cross while the menu is open */
.menu-toggle__icon {
  position: relative;
  width: 16px;
  height: 8px;
}

.menu-toggle__icon i {
  position: absolute;
  left: 0;
  width: 100%;
  height: 1.5px;
  background: currentColor;
  transition:
    transform 0.5s var(--ease-roll),
    width 0.5s var(--ease-roll);
}

.menu-toggle__icon i:first-child {
  top: 0;
}

.menu-toggle__icon i:last-child {
  bottom: 0;
  width: 60%;
}

.menu-toggle:hover .menu-toggle__icon i:last-child {
  width: 100%;
}

.menu-toggle[aria-expanded="true"] .menu-toggle__icon i:first-child {
  transform: translateY(3.25px) rotate(45deg);
}

.menu-toggle[aria-expanded="true"] .menu-toggle__icon i:last-child {
  width: 100%;
  transform: translateY(-3.25px) rotate(-45deg);
}

/* Tablet and mobile: the bar fills the width and the header button is hidden */
@media (max-width: 1023px) {
  .site-header {
    grid-template-columns: 1fr;
  }

  .site-header__bar {
    grid-column: 1;
    justify-content: space-between;
  }

  .site-header .site-header__cta {
    display: none;
  }

  .clock {
    flex: 1;
    justify-content: center;
  }
}

/* Small phones: drop the secondary words so the bar fits */
@media (max-width: 420px) {
  .wordmark__sub,
  .clock__tz {
    display: none;
  }
}


/* === 2. Buttons ============================================================
   The fill dissolves in pixel by pixel (pixelate() in ui.js); variants only set the --btn-* values. */

.btn {
  --btn-fg: currentColor;       /* text colour */
  --btn-bg: transparent;        /* background colour */
  --btn-line: currentColor;     /* 1px outline colour */
  --btn-fill: var(--hivis);     /* hover fill colour */
  --btn-fill-fg: var(--ink);    /* text colour on top of the fill */
  --btn-h: 3rem;                /* height, also the width of the icon cell */

  position: relative;
  isolation: isolate;           /* keeps the fill (z-index: -1) inside the button */
  display: inline-flex;
  align-items: stretch;
  min-height: var(--btn-h);
  overflow: hidden;
  color: var(--btn-fg);
  background: var(--btn-bg);
  box-shadow: inset 0 0 0 1px var(--btn-line);
  font-family: var(--font-mono);
  font-size: 0.71875rem;
  font-weight: 500;
  line-height: 1;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  white-space: nowrap;
  -webkit-tap-highlight-color: transparent;

  /* The text colour changes just after the fill has started to appear */
  transition:
    color 0.12s linear 0.14s,
    box-shadow var(--dur-2) var(--ease-out);
}

.btn__fill {
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--btn-fill);

  /* Flip-book mask from pixelate(); solid by default so the fill works before it runs */
  -webkit-mask-image: var(--pixel-mask, linear-gradient(#000, #000));
  mask-image: var(--pixel-mask, linear-gradient(#000, #000));
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-size: var(--pixel-size, 100% 100%);
  mask-size: var(--pixel-size, 100% 100%);
  -webkit-mask-position: 0% 0%;
  mask-position: 0% 0%;
  transition:
    -webkit-mask-position 0.46s steps(var(--pixel-steps, 1), jump-end),
    mask-position 0.46s steps(var(--pixel-steps, 1), jump-end);
}

/* Before pixelate() has run (no data-pixel yet): a simple slide-up fill */
.btn:not([data-pixel]) .btn__fill {
  transform: translateY(101%);
  transition: transform 0.5s var(--ease-roll);
}

/* The label is a one-line mask; its copy waits just below and rolls up on hover */
.btn__label {
  display: block;
  align-self: center;
  height: 1.3em;
  margin: 0 1.2rem;
  overflow: hidden;
}

.btn__label > span {
  position: relative;
  display: block;
  line-height: 1.3;
  transition: transform 0.5s var(--ease-roll);
}

.btn__label > span::after {
  content: attr(data-text);
  position: absolute;
  top: 100%;
  left: 0;
}

/* Icon cell with a dotted divider; --ix / --iy = the direction the arrow leaves on hover */
.btn__icon {
  --ix: 260%;
  --iy: 0%;
  position: relative;
  display: grid;
  flex: none;
  place-items: center;
  width: var(--btn-h);
  overflow: hidden;
  background-image: linear-gradient(currentColor 50%, transparent 0);
  background-size: 1px 6px;
  background-repeat: repeat-y;
  background-position: 0 0;
}

/* North-east arrow variant: the arrow leaves towards the top right */
.btn--ne .btn__icon {
  --ix: 260%;
  --iy: -260%;
}

.btn__icon svg {
  grid-area: 1 / 1;          /* both arrows share the same cell */
  width: 16px;
  height: 16px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  transition: transform 0.5s var(--ease-roll);
}

/* The second arrow waits outside the cell, on the opposite side */
.btn__icon svg:last-child {
  transform: translate(calc(var(--ix) * -1), calc(var(--iy) * -1));
}

/* Hover effects only on devices with a real hover (not touch screens) */
@media (hover: hover) {
  .btn:hover {
    color: var(--btn-fill-fg);
  }

  .btn:hover .btn__fill {
    -webkit-mask-position: 100% 0%;
    mask-position: 100% 0%;
  }

  .btn:not([data-pixel]):hover .btn__fill {
    transform: none;
  }

  .btn:hover .btn__label > span {
    transform: translateY(-100%);
  }

  .btn:hover .btn__icon svg:first-child {
    transform: translate(var(--ix), var(--iy));
  }

  .btn:hover .btn__icon svg:last-child {
    transform: none;
  }
}

/* Keyboard focus shows the same filled state as hover */
.btn:focus-visible {
  color: var(--btn-fill-fg);
}

.btn:focus-visible .btn__fill {
  -webkit-mask-position: 100% 0%;
  mask-position: 100% 0%;
  transform: none;
}

/* Pressed */
.btn:active {
  transform: translateY(1px);
}

/* Disabled and busy (while the enquiry form is sending) */
.btn[disabled],
.btn.is-busy {
  pointer-events: none;
}

.btn[disabled] {
  opacity: 0.45;
}

/* Variants ------------------------------------------------------------------- */

/* Outline button (header). Adapts when the header is over a light section. */
.btn--line {
  --btn-line: rgba(245, 243, 238, 0.5);
  --btn-bg: rgba(16, 17, 18, 0.18);
}

.is-on-light .btn--line {
  --btn-line: rgba(16, 17, 18, 0.45);
  --btn-bg: rgba(230, 226, 218, 0.4);
  --btn-fill: var(--ink);
  --btn-fill-fg: var(--bone);
}

/* Translucent dark button over photographs (hero "View project") */
.btn--glass {
  --btn-bg: rgba(16, 17, 18, 0.46);
  --btn-line: rgba(245, 243, 238, 0.32);
  --btn-fg: var(--bone);
}

/* Solid ink button (enquiry "Send enquiry") */
.btn--solid {
  --btn-bg: var(--ink);
  --btn-fg: var(--bone);
  --btn-line: var(--ink);
}

/* Hi-vis button, with a light fill on hover */
.btn--hivis {
  --btn-bg: var(--hivis);
  --btn-fg: var(--ink);
  --btn-line: var(--hivis);
  --btn-fill: var(--bone);
  --btn-fill-fg: var(--ink);
}

/* Scramble button (About): label re-typed on hover (initScramble in ui.js); text turns ink on the fill */
.btn--scramble {
  --btn-bg: rgba(16, 17, 18, 0.72);
  --btn-fg: var(--bone);
  --btn-line: transparent;
  --btn-fill: var(--hivis);
  --btn-fill-fg: var(--ink);
  align-items: center;
  gap: 1.1rem;
  min-height: 2.5rem;
  padding: 0 0.95rem 0 1rem;
  font-size: 0.8125rem;
  letter-spacing: 0.06em;
}

.btn--scramble__text {
  display: inline-block;
  white-space: pre;                     /* keep spaces while letters are swapped */
  font-variant-numeric: tabular-nums;
}

.btn--scramble__icon {
  width: 18px;
  height: 18px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  transition: transform var(--dur-3) var(--ease-roll);
}

.btn--scramble:hover .btn--scramble__icon,
.btn--scramble:focus-visible .btn--scramble__icon {
  transform: translateX(4px);
}

/* Square icon button (menu close, case study and viewer controls) ------------ */

.icon-btn {
  position: relative;
  display: grid;
  place-items: center;
  width: 2.75rem;
  height: 2.75rem;
  color: inherit;
  box-shadow: inset 0 0 0 1px var(--line, currentColor);
  transition:
    background-color var(--dur-2) var(--ease-out),
    color var(--dur-2) var(--ease-out);
}

.icon-btn svg {
  width: 18px;
  height: 18px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  transition: transform var(--dur-3) var(--ease-roll);
}

/* On hover the button fills with its own text colour and the icon inverts */
@media (hover: hover) {
  .icon-btn:hover {
    background: currentColor;
  }

  .icon-btn:hover svg {
    stroke: var(--icon-hover, var(--graphite));
  }
}

[data-theme="light"] .icon-btn,
.case .icon-btn {
  --icon-hover: var(--bone);
}


/* === 3. Custom cursor ======================================================
   Active with .has-cursor (initCursor in ui.js); --x / --y = pointer, --fx / --fy = delayed frame. */

.cursor {
  position: fixed;
  top: 0;
  left: 0;
  z-index: var(--z-cursor);
  display: none;
  width: 0;
  height: 0;
  color: #fff;
  mix-blend-mode: difference;
  pointer-events: none;
}

.has-cursor .cursor {
  display: block;
}

/* Hide the system cursor where the custom one takes over */
.has-cursor,
.has-cursor a,
.has-cursor button,
.has-cursor label,
.has-cursor [data-cursor] {
  cursor: none;
}

/* Keep the native cursor where it helps: text fields and selects */
.has-cursor input,
.has-cursor textarea {
  cursor: text;
}

.has-cursor select {
  cursor: pointer;
}

.cursor__cross,
.cursor__frame,
.cursor__tag {
  position: absolute;
  top: 0;
  left: 0;
  will-change: transform;
}

/* Crosshair: four short lines drawn with background gradients */
.cursor__cross {
  width: 25px;
  height: 25px;
  margin: -12.5px 0 0 -12.5px;
  transform: translate3d(var(--x, -100px), var(--y, -100px), 0);
  background:
    linear-gradient(currentColor, currentColor) 0 12px / 9px 1px no-repeat,
    linear-gradient(currentColor, currentColor) 16px 12px / 9px 1px no-repeat,
    linear-gradient(currentColor, currentColor) 12px 0 / 1px 9px no-repeat,
    linear-gradient(currentColor, currentColor) 12px 16px / 1px 9px no-repeat;
  transition: opacity var(--dur-2);
}

/* Corner brackets that close in around links and buttons */
.cursor__frame {
  width: 46px;
  height: 46px;
  margin: -23px 0 0 -23px;
  transform: translate3d(var(--fx, -100px), var(--fy, -100px), 0);
}

.cursor__frame i {
  position: absolute;
  width: 9px;
  height: 9px;
  border: 0 solid currentColor;
  opacity: 0;
  transition:
    opacity var(--dur-2) var(--ease-out),
    transform var(--dur-3) var(--ease-out);
}

.cursor__frame i:nth-child(1) {
  top: 0;
  left: 0;
  border-width: 1px 0 0 1px;
  transform: translate(9px, 9px);
}

.cursor__frame i:nth-child(2) {
  top: 0;
  right: 0;
  border-width: 1px 1px 0 0;
  transform: translate(-9px, 9px);
}

.cursor__frame i:nth-child(3) {
  bottom: 0;
  right: 0;
  border-width: 0 1px 1px 0;
  transform: translate(-9px, -9px);
}

.cursor__frame i:nth-child(4) {
  bottom: 0;
  left: 0;
  border-width: 0 0 1px 1px;
  transform: translate(9px, -9px);
}

/* .is-active: over something clickable */
.cursor.is-active .cursor__frame i {
  opacity: 1;
  transform: none;
}

.cursor.is-active .cursor__cross {
  opacity: 0.5;
}

/* Tag: the data-cursor word (for example "Open") above the X / Y readout */
.cursor__tag {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding-top: 16px;
  padding-left: 20px;
  transform: translate3d(var(--x, -100px), var(--y, -100px), 0);
  font-family: var(--font-mono);
  font-size: 0.625rem;
  font-weight: 500;
  line-height: 1.2;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  white-space: nowrap;
}

.cursor__tag [data-cursor-label]:empty {
  display: none;
}

.cursor__tag [data-cursor-xy] {
  opacity: 0.62;
  font-variant-numeric: tabular-nums;
}

.cursor.is-active .cursor__tag {
  padding-top: 22px;
  padding-left: 30px;
}

/* .is-hidden: pointer has left the window, or is over a text field */
.cursor.is-hidden {
  opacity: 0;
}


/* === 4. Loader =============================================================
   main.js draws the paths, raises the level (--level: 0 top, 1 bottom), then lifts the panels. */

.loader {
  display: none;
}

.js .loader {
  position: fixed;
  inset: 0;
  z-index: var(--z-loader);
  display: grid;
  place-items: center;
  color: var(--bone);
}

.loader__panels {
  position: absolute;
  inset: 0;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
}

.loader__panels span {
  background: var(--graphite);
  box-shadow: inset -1px 0 0 rgba(245, 243, 238, 0.06);
}

.loader__drawing {
  position: relative;
  width: min(70vw, 600px);
  aspect-ratio: 600 / 440;
}

.loader__svg {
  width: 100%;
  height: 100%;
  overflow: visible;
}

/* Every path starts hidden: dash length 1, offset 1 (pathLength="1") */
.loader__lines path {
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
  opacity: 0.8;
}

/* The laser level: wider than the drawing, positioned by --level */
.loader__level {
  --level: 0.91;
  position: absolute;
  top: calc(var(--level) * 100%);
  left: -14vw;
  right: -14vw;
  height: 0;
}

.loader__level-line {
  position: absolute;
  inset: 0 0 auto;
  height: 1px;
  background: var(--hivis);
  box-shadow: 0 0 12px rgba(220, 245, 60, 0.6);
}

.loader__level-tag {
  position: absolute;
  right: 14vw;
  bottom: 6px;
  display: flex;
  gap: 0.8em;
  color: var(--hivis);
  font-family: var(--font-mono);
  font-size: var(--fs-label);
  font-weight: 500;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  font-variant-numeric: tabular-nums;
}

/* "OMFC International" in the bottom-left corner */
.loader__meta {
  position: absolute;
  left: var(--margin);
  right: var(--margin);
  bottom: var(--margin);
  display: flex;
  justify-content: flex-start;
  gap: var(--s-4);
  color: var(--muted-on-dark);
  font-family: var(--font-mono);
  font-size: var(--fs-label);
  letter-spacing: var(--track-label);
  text-transform: uppercase;
}


/* === 5. Menu ===============================================================
   Full-screen dialog: panels drop in, then the links rise (initMenu in ui.js). */

.menu {
  position: fixed;
  inset: 0;
  z-index: var(--z-menu);
  overflow: hidden;
  color: var(--bone);
}

.menu__panels {
  position: absolute;
  inset: 0;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
}

.menu__panels span {
  background: var(--graphite);
  box-shadow: inset -1px 0 0 rgba(245, 243, 238, 0.07);
  transform-origin: 50% 0;
}

/* Rows: [close button] / [links + preview] / [footer line] */
.menu__inner {
  position: relative;
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  grid-template-rows: auto 1fr auto;
  column-gap: var(--gutter);
  height: 100%;
  padding: var(--header-top) var(--margin) var(--margin);
  overflow-y: auto;
}

/* Close button, top right */
.menu__top {
  grid-column: 1 / -1;
  display: flex;
  justify-content: flex-end;
  align-items: center;
  min-height: var(--header-h);
  color: var(--muted-on-dark);
}

.menu__close {
  --line: var(--line-on-dark);
  color: var(--bone);
}

.menu__nav {
  grid-column: 1 / span 8;
  align-self: center;
  padding-block: var(--s-7);
}

/* Each link rises out of its own mask when the menu opens */
.menu__list li {
  overflow: hidden;
}

.menu__list a {
  display: flex;
  align-items: baseline;
  gap: clamp(0.75rem, 2vw, 2rem);
  padding-block: 0.04em;
  font-family: var(--font-narrow);
  font-size: clamp(2.4rem, 6.2vh + 2.4vw, 7rem);
  font-weight: 300;
  font-stretch: 68%;
  line-height: 0.94;
  letter-spacing: -0.005em;
  text-transform: uppercase;
  transition:
    opacity var(--dur-3) var(--ease-out),
    color var(--dur-2);
}

/* Small number before each link (01 to 07) */
.menu__no {
  font-family: var(--font-mono);
  font-size: var(--fs-label);
  font-weight: 500;
  font-stretch: 100%;
  letter-spacing: var(--track-label);
  opacity: 0.5;
  transform: translateY(-1.6em);
}

/* Link roll: the hi-vis copy (from data-text) rolls up on hover */
.menu__text {
  display: block;
  overflow: hidden;
}

.menu__text > span {
  position: relative;
  display: block;
  transition: transform 0.6s var(--ease-roll);
}

.menu__text > span::after {
  content: attr(data-text);
  position: absolute;
  top: 100%;
  left: 0;
  color: var(--hivis);
}

@media (hover: hover) {
  /* Dim the other links while one is hovered */
  .menu__list:hover a {
    opacity: 0.32;
  }

  .menu__list a:hover,
  .menu__list a:focus-visible {
    opacity: 1;
  }

  .menu__list a:hover .menu__text > span {
    transform: translateY(-100%);
  }
}

/* Photograph preview for the hovered link */
.menu__preview {
  grid-column: 9 / -1;
  align-self: center;
  max-height: 68vh;
  aspect-ratio: 3 / 4;
  overflow: hidden;
  background: var(--graphite-2);
}

.menu__preview img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Footer line with the London time, bottom right */
.menu__foot {
  grid-column: 1 / -1;
  display: flex;
  justify-content: flex-end;
  align-items: flex-end;
  gap: var(--s-5);
  padding-top: var(--s-5);
  border-top: 1px solid var(--line-on-dark);
  color: var(--muted-on-dark);
  font-family: var(--font-mono);
  font-size: var(--fs-label);
  line-height: 1.6;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
}

.menu__time time {
  color: var(--bone);
  font-variant-numeric: tabular-nums;
}

/* Mobile: links only, no preview */
@media (max-width: 767px) {
  .menu__inner {
    grid-template-columns: 1fr;
  }

  .menu__nav {
    grid-column: 1 / -1;
  }

  .menu__preview {
    display: none;
  }
}


/* === 6. Hold-to-install button (In focus) ==================================
   --p (0 to 1, set by focus.js) drives the ring and the hi-vis disc. */

.hold {
  --p: 0;
  position: relative;
  display: grid;
  place-items: center;
  width: 7.25rem;
  height: 7.25rem;
  border-radius: 50%;
  color: var(--ink);
  transition: transform var(--dur-3) var(--ease-out);

  /* Holding a finger down must not select text or open a context menu */
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
  touch-action: manipulation;
}

/* Hi-vis disc that grows from the centre as the button is held */
.hold::before {
  content: "";
  position: absolute;
  inset: 10px;
  border-radius: 50%;
  background: var(--hivis);
  transform: scale(var(--p));
  transition: transform 0.08s linear;
}

/* Inner hairline circle */
.hold::after {
  content: "";
  position: absolute;
  inset: 10px;
  border-radius: 50%;
  box-shadow: inset 0 0 0 1px var(--line-on-light);
}

/* The ring starts at 12 o'clock */
.hold__ring {
  position: absolute;
  inset: 0;
  overflow: visible;
  transform: rotate(-90deg);
}

.hold__track {
  fill: rgba(245, 243, 238, 0.7);
  stroke: var(--line-on-light);
  stroke-width: 1;
}

/* pathLength="1" in the markup: offset 1 = empty ring, 0 = full ring */
.hold__progress {
  fill: none;
  stroke: var(--ink);
  stroke-width: 2.5;
  stroke-dasharray: 1;
  stroke-dashoffset: calc(1 - var(--p));
}

.hold__label {
  position: relative;
  z-index: 1;
  display: grid;
  text-align: center;
  font-family: var(--font-mono);
  font-size: 0.625rem;
  font-weight: 500;
  line-height: 1.5;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
}

.hold:hover {
  transform: scale(1.04);
}

/* Pressed in while holding */
.hold.is-holding {
  transform: scale(0.95);
}

/* Finished: full disc, no further interaction */
.hold.is-done {
  pointer-events: none;
}

.hold.is-done::before {
  transform: scale(1);
}


/* === 7. Photo viewer ==================================================== */

.viewer {
  --line: var(--line-on-dark);
  position: fixed;
  inset: 0;
  z-index: var(--z-viewer);
  display: grid;
  background: rgba(13, 14, 15, 0.97);
  color: var(--bone);
}

/* Image on top, caption underneath */
.viewer__figure {
  display: grid;
  grid-template-rows: 1fr auto;
  justify-items: center;
  gap: var(--s-4);
  min-height: 0;
  padding: calc(var(--header-top) + 3.5rem) var(--margin) var(--margin);
}

.viewer__img {
  width: auto;
  min-height: 0;
  max-height: 100%;
  object-fit: contain;
  user-select: none;
  -webkit-user-drag: none;
}

.viewer__caption {
  display: flex;
  gap: var(--s-4);
  max-width: 70ch;
  color: rgba(245, 243, 238, 0.8);
  font-size: var(--fs-small);
  line-height: 1.5;
}

.viewer__caption .label {
  flex: none;
  padding-top: 0.15em;
  color: var(--hivis);
}

/* Previous / next / close, top right */
.viewer__controls {
  position: absolute;
  top: var(--header-top);
  right: var(--margin);
  display: flex;
  gap: var(--s-2);
}
