/* - - - - - - - - - - - - - - - - - - - - *\
TOKENS — mirrors adamruf.com's current dark/neon system
\* - - - - - - - - - - - - - - - - - - - - */
:root {
  --bg: #010101;
  --bg-raised: #121212;
  --fg: #AEFF00;
  --fg-dim: rgba(174, 255, 0, 0.5);
  --fg-faint: rgba(174, 255, 0, 0.18);
  --accent-yellow: #FFEE00;
  --warn: #FFB300;
  --white: #F6F6F6;
  --muted: #8a8a8a;
  /* Monochrome, not lime-tinted — same opacity as before (0.22), matching
     the neutral-gray idiom the rest of the UI already uses for structural
     chrome (.ring-track is rgba(255,255,255,0.08), resting .round-dot is
     0.16) rather than tinting every container edge green. Keeps lime
     meaningful (selected chips, labels, toggles) instead of diluting it
     into borders too. */
  --border: rgba(255, 255, 255, 0.22);

  /* Matches the holofoil gradient from adamruf.com (pulled from its shipped CSS):
     green into fading yellow into fading orange, on a 63.43deg diagonal. Used
     for text/border accents (needs the opaque base layer below it). One
     accent color for both Work and Rest now — ring width (and position,
     nested vs. inner) carries the phase distinction instead of color. */
  --holofoil: linear-gradient(63.43deg, #AEFF00 41.67%, rgba(255, 238, 0, 0.6) 66.67%, rgba(255, 204, 0, 0.4) 83.33%);
  --holofoil-base: linear-gradient(90deg, #AEFF00 0% 100%);

  /* The "Email Adam" button recipe from adamruf.com (pulled from its shipped
     CSS, data-astro-cid-ekguhzzh) — rest/hover/active gradients + matching
     shadow/border/transform per state. Used for solid CTA buttons. */
  --holofoil-btn: linear-gradient(81.86deg, rgba(136, 255, 0, 0.8) 4.89%, rgba(206, 255, 0, 0.8) 78.31%, rgba(238, 255, 0, 0.8) 97.89%);
  --holofoil-btn-base: #A7F500;
  --holofoil-btn-active: linear-gradient(73.5deg, #AEFF00 25%, #EEFF00 64%, #A2FFC6 100%);
  --holofoil-btn-active-base: #AEFF00;
  --holofoil-btn-shadow: 0 1px 2px rgba(0, 0, 0, 0.08), 0 2px 2px rgba(0, 0, 0, 0.04);

  --font-mono: 'Space Mono', 'SF Mono', Menlo, monospace;

  --radius: 0.5rem; /* 8px — buttons and settings-section cards (.stepper-group, .sound-settings, .toggle-row) */
  --control-radius: 0.5rem; /* 8px — rounded-rect shared by steppers, chips, icon buttons */
  --tap-min: 4rem; /* 64px — comfortably above the 44px a11y minimum */

  color-scheme: dark;
}

* { box-sizing: border-box; }

/* Mirrors adamruf.com's LavaBackground.astro verbatim — keep in sync if that
   component's position/z-index ever changes. */
.lava-canvas {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
  pointer-events: none;
}

/* Mirrors adamruf.com's Breadcrumb.astro verbatim — keep in sync if that
   component's position/typography/color ever changes. */
.breadcrumb {
  position: fixed;
  top: 2.5rem;
  left: 1.5rem;
  z-index: 10;
  display: flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-mono);
  font-size: 1rem;
  margin: 0;
}

/* The installed app drops the page-chrome that only made sense inside a
   browser tab: site navigation (there's no address bar to navigate "away"
   from), the ambient lava texture, and the top/bottom vignettes that
   existed to keep content legible over that texture near the fixed
   breadcrumb/edges. None of that applies once it's running standalone —
   #app's own padding is pared back to just a safe-area-aware minimum below
   (see #app) now that there's nothing left to clear. */
@media (display-mode: standalone) {
  .breadcrumb,
  .lava-canvas,
  .top-fade,
  .fade-overlay {
    display: none;
  }
}

@media (min-width: 696px) {
  .breadcrumb {
    left: 2.5rem;
  }
}

.breadcrumb a {
  color: #aaa;
  text-decoration: none;
  transition: color 0.15s ease;
}

.breadcrumb a:hover {
  color: #fff;
}

.breadcrumb__sep {
  color: #444;
}

.breadcrumb__current {
  color: #AEFF00;
}

/* Mirrors adamruf.com's Breadcrumb.astro dropdown verbatim — keep in sync
   if that component's nav markup/styles ever change. */
.breadcrumb__nav {
  position: relative;
}

.breadcrumb__nav summary {
  display: flex;
  align-items: center;
  gap: 4px;
  list-style: none;
  cursor: pointer;
}

.breadcrumb__nav summary::-webkit-details-marker {
  display: none;
}

.breadcrumb__chevron {
  transition: transform 0.15s ease;
}

.breadcrumb__nav[open] .breadcrumb__chevron {
  transform: rotate(180deg);
}

.breadcrumb__menu {
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  display: flex;
  flex-direction: column;
  width: max-content;
  min-width: 100%;
  margin: 0;
  padding: 6px;
  list-style: none;
  background: rgba(20, 20, 20, 0.85);
  backdrop-filter: blur(24px) saturate(160%);
  -webkit-backdrop-filter: blur(24px) saturate(160%);
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 10px;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.07),
    0 8px 24px rgba(0, 0, 0, 0.4);
}

.breadcrumb__menu a {
  display: block;
  padding: 6px 10px;
  border-radius: 6px;
  color: #ccc;
  font-size: 0.9375rem;
  white-space: nowrap;
}

.breadcrumb__menu a:hover {
  color: #fff;
  background: rgba(255, 255, 255, 0.08);
}

/* Mirrors adamruf.com's FadeOverlays.astro verbatim — keep in sync if that
   component's gradients/z-index ever change. */
.top-fade {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 130px;
  background: linear-gradient(
    to bottom,
    #010101 0%,
    #010101 40%,
    rgba(1, 1, 1, 0.93) 55%,
    rgba(1, 1, 1, 0.78) 66%,
    rgba(1, 1, 1, 0.58) 76%,
    rgba(1, 1, 1, 0.36) 85%,
    rgba(1, 1, 1, 0.16) 93%,
    transparent 100%
  );
  pointer-events: none;
  z-index: 9;
}

.fade-overlay {
  position: fixed;
  bottom: 0;
  left: 0;
  width: 100%;
  height: 100px;
  background: linear-gradient(
    to top,
    #010101 0%,
    rgba(1, 1, 1, 0.94) 15%,
    rgba(1, 1, 1, 0.82) 28%,
    rgba(1, 1, 1, 0.65) 40%,
    rgba(1, 1, 1, 0.46) 52%,
    rgba(1, 1, 1, 0.28) 64%,
    rgba(1, 1, 1, 0.14) 76%,
    rgba(1, 1, 1, 0.05) 88%,
    transparent 100%
  );
  pointer-events: none;
  z-index: 5;
}

html, body {
  margin: 0;
  padding: 0;
  width: 100%;
  background: var(--bg);
  color: var(--white);
}

body {
  font-family: var(--font-mono);
  min-height: 100dvh;
  overflow-x: hidden;
  -webkit-tap-highlight-color: transparent;
}

/* Fixed to the viewport (height, not min-height) so the Done footer can
   never scroll out of view on a short mobile screen — the setup screen's
   own content scrolls internally instead (see .setup-scroll). */
#app {
  height: 100dvh;
  /* Sits above .lava-canvas (z-index 0) the same way good-riddance's
     .cd-shell does, so the ambient background doesn't paint over the UI. */
  position: relative;
  z-index: 2;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  /* Top/bottom padding clears .top-fade (130px) and .fade-overlay (100px)
     with an 8px-grid gap to spare (144-130=14px, 112-100=12px) — those
     overlays sit at z-index 9/5, above #app's own z-index 2, so content
     left inside their band reads dimmed/washed out instead of clearly
     lit. This also satisfies (with room to spare) the >=24px gap
     .app-header needs below the breadcrumb, so that margin doesn't need
     its own separate top padding on top of this. Safe-area insets add on
     top of the fade clearance, not in place of it, since a notch eats into
     the same space the fade already claims. */
  padding: max(144px, calc(env(safe-area-inset-top) + 24px)) max(1.5rem, env(safe-area-inset-right)) max(112px, calc(env(safe-area-inset-bottom) + 24px)) max(1.5rem, env(safe-area-inset-left));
}

/* Standalone has no breadcrumb or fades left to clear (see the
   display-mode: standalone block above .breadcrumb), so #app's padding
   drops back to a plain safe-area-aware minimum instead of the 144px/112px
   reserved for them — the installed app gets that space back for the ring. */
@media (display-mode: standalone) {
  #app {
    padding: max(1.5rem, env(safe-area-inset-top)) max(1.5rem, env(safe-area-inset-right)) max(1.5rem, env(safe-area-inset-bottom)) max(1.5rem, env(safe-area-inset-left));
  }
}

.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* - - - - - - - - - - - - - - - - - - - - *\
FOCUS — pulsing ring, matches site a11y pattern
\* - - - - - - - - - - - - - - - - - - - - */
@keyframes focus-pulse {
  0%, 100% { outline-color: rgba(174, 255, 0, 0.3); }
  50%      { outline-color: rgba(174, 255, 0, 0.75); }
}

:focus-visible {
  outline: 4px solid rgba(174, 255, 0, 0.3);
  outline-offset: 3px;
  border-radius: 6px;
  animation: focus-pulse 1.8s ease-in-out infinite;
}

@media (prefers-reduced-motion: reduce) {
  :focus-visible { animation: none; }
}

/* - - - - - - - - - - - - - - - - - - - - *\
HEADER
\* - - - - - - - - - - - - - - - - - - - - */
/* Centered wordmark on the run screen. Hidden on setup — with the custom
   steppers and volume slider, setup already runs long on mobile, and the
   wordmark was purely decorative there (settings access lives entirely in
   run-controls); dropping it buys back vertical space for the scrollable
   content above the fixed Done footer (see .setup-scroll below). */
#app[data-screen="setup"] .app-header {
  display: none;
}

.app-header {
  text-align: center;
  /* #app's own top padding (144px, see above) already clears the
     breadcrumb (ends ~59px down) by well over the required 24px, so no
     extra margin is needed here just for that. Trimmed from 1.5rem — on a
     short window the ring (vmin-sized, so it doesn't know how much of
     .run-content's height the wordmark+gap above it already claimed) can
     end up overflowing enough to crop against .run-controls below; this
     buys a little of that room back directly. */
  margin-bottom: 1rem; /* 16px */
}

.wordmark {
  /* inline-flex + align-items: center, not inline-block + text-align:
     center — the dots are shorter/fixed-height spans sitting between tall
     uppercase letters, and vertical-align: middle (see .wordmark-dot)
     aligns to a point derived from font metrics (roughly mid-x-height),
     which reads visibly low against full-height caps. Flex instead
     vertically centers every piece — the dot spans and the plain-text
     runs between them alike — against the row's own actual height, so the
     dots land on the true visual center of the letters next to them. */
  display: inline-flex;
  align-items: center;
  /* The dots sit mid-word and the wordmark is centered, so collapsing them
     shrinks this element and both edges shift inward. A fixed min-width
     keeps this box's own size (and edges) constant; the text just
     re-centers inside it as the dots collapse/expand. */
  min-width: 15ch; /* extra buffer past the ~13ch estimate — letter-spacing isn't accounted for in the ch unit, so a tight estimate still let the box shrink by a hair */
  justify-content: center;
  cursor: default;
  user-select: none;
  font-family: var(--font-mono);
  text-transform: uppercase;
  font-size: 1.5rem;
  font-weight: 700;
  letter-spacing: 0.04em;
}

/* Reuses .round-dot for its fill color/shape — an empty span rather than a
   "•" character, since a real character would inherit the parent's
   holofoil gradient text-fill like the letters do, competing with it
   instead of reading as a plain separator. Just resizes it for inline use
   next to the (much smaller) wordmark text. */
.round-dot.wordmark-dot {
  /* .wordmark is flex now (see above), which vertically centers this
     against its row on its own — no vertical-align needed, and it
     wouldn't do anything on a flex item anyway. */
  display: inline-block;
  margin: 0 0.15em;
  overflow: hidden;
  transition: opacity 0.25s ease, filter 0.25s ease, width 0.25s ease, margin 0.25s ease;
}

/* Same behavior on every device/viewport, not just touch (where it started
   — no hover there to trigger a collapse dynamically, so it used to be
   scoped to @media (hover: none) and desktop just left the dots expanded
   permanently, collapsing only on hover). Starting condensed and
   expanding into the dot-divided wordmark once a session actually begins
   (#app.session-active, set in app.js) reads as more intentional than a
   hover-only flourish, and is the one consistent behavior everywhere.
   width/margin animate to/from 0 right alongside the fade/blur (not just
   hidden in place), so the letters actually slide together into one tight
   word rather than leaving gaps — riding the same transition already
   declared on .round-dot.wordmark-dot above. */
.wordmark .wordmark-dot {
  opacity: 0;
  filter: blur(2px);
  width: 0;
  margin-left: 0;
  margin-right: 0;
}
#app.session-active .wordmark .wordmark-dot {
  opacity: 1;
  filter: none;
  width: 16px;
  margin-left: 0.15em;
  margin-right: 0.15em;
}

.icon-btn {
  appearance: none;
  -webkit-appearance: none;
  width: var(--tap-min);
  height: var(--tap-min);
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  border-radius: var(--control-radius);
  background: transparent;
  color: var(--white);
  cursor: pointer;
  transition: background-image 0.15s ease, color 0.15s ease, transform 0.1s ease;
}
/* Secondary buttons (settings, reset) stay plain — no holofoil, that's
   reserved for the primary CTA. Hover/press just use the same neutral
   grays as the ring track/round indicators (0.08 / 0.16 white) so they
   read as "quiet" controls rather than competing calls to action. */
.icon-btn:not(.icon-btn-primary):hover,
.icon-btn:not(.icon-btn-primary):focus-visible {
  background-color: rgba(255, 255, 255, 0.08);
}
.icon-btn:not(.icon-btn-primary):active {
  background-color: rgba(255, 255, 255, 0.16);
  transform: scale(0.92);
}
/* Settings is reachable from the run screen, but only while paused —
   editing config mid-interval isn't allowed. Force it back to the resting
   plain look even on hover so there's no holofoil hint that it's clickable. */
.icon-btn:disabled,
.icon-btn:disabled:hover,
.icon-btn:disabled:focus-visible,
.icon-btn:disabled:active {
  background-image: none;
  background-color: transparent;
  color: var(--muted);
  opacity: 0.4;
  cursor: not-allowed;
  pointer-events: none;
  transform: none;
}
.icon { width: 1.5rem; height: 1.5rem; }
.icon[hidden] { display: none; }

main {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 0; /* lets flex children actually shrink/scroll instead of overflowing #app */
}

.screen {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
  width: min(560px, 100%);
  margin: 0 auto;
  min-height: 0;
}

/* Tighter than .screen's shared 1.5rem (run-screen still uses that, between
   the ring and its controls) — frees up a bit more height for
   .setup-scroll-frame without touching Done's own size or #app's
   fade-clearance padding, neither of which has room to give. */
#setup-screen {
  gap: 1rem;
}

.screen[hidden] { display: none; }

/* The settings groups (Interval/Rest/Rounds/toggles) live in this one
   bounded box — flex: 1 + min-height: 0 pins its height to whatever's
   actually left over in .screen (not to its own content), so it never
   grows to push .done-group (outside it, fixed in place below) off-screen;
   overflow-y: auto (on the inner .setup-scroll below) handles anything that
   doesn't fit by scrolling within that fixed box instead. Split into an
   outer frame (border/radius) and an inner scroller (overflow, padding) —
   the border lives on the outer element so it reads as one continuous
   frame around whatever's visible, independent of inner scroll padding. */
/* Same dark-glass recipe as .ring-wrap::before and adamruf.com's
   ghibli-ranking .card *hover* state — permanent here rather than
   hover-triggered, same reasoning as the ring's version. overflow: hidden
   (for clipping the scrolling content's corners) doesn't clip this box's
   own box-shadow — that's a separate paint step from content clipping. */
.setup-scroll-frame {
  flex: 1;
  min-height: 0;
  background: rgba(255, 255, 255, 0.08);
  border: 1px solid rgba(255, 255, 255, 0.4);
  border-radius: var(--radius);
  box-shadow: 0 0 20px rgba(255, 255, 255, 0.15);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  overflow: hidden;
}

.setup-scroll {
  height: 100%;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
  /* Same 1rem on all four sides — content (including the first group's
     floating .group-label, which pokes up above its own box) sits an equal
     distance from the frame on every edge, not padded more generously on
     the sides than top/bottom. No edge fade here: the frame's own border
     already marks this as a bounded, scrollable box, so content can just
     scroll right up to it rather than needing a dimming effect to hint
     that. */
  padding: 1rem;
}

/* - - - - - - - - - - - - - - - - - - - - *\
SETUP SCREEN
\* - - - - - - - - - - - - - - - - - - - - */
.stepper-group {
  position: relative;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 1.75rem 1rem 1.25rem;
  margin: 0;
}

/* .screen's gap is a flex gap, not a margin — negative margins don't
   collapse into it. Grouping total+button with their own 1rem (16px) gap
   is what actually anchors the total to the CTA; the group as a whole
   still gets the normal .screen gap relative to the section above it. */
/* No longer needs margin-top: auto to anchor itself — now that it's a
   sibling of .setup-scroll (not a sibling of the settings groups
   themselves), .setup-scroll's flex: 1 already consumes all the leftover
   space, which pins this to the bottom on its own. Fixed in place, not
   scrollable (see #app/.setup-scroll), so Done is always reachable. */
.done-group {
  display: flex;
  flex-direction: column;
  gap: 1.5rem; /* 24px */
  flex-shrink: 0;
}

/* Last item inside .setup-scroll (not .done-group) — #app has no page-level
   scroll of its own (height: 100dvh, overflow: hidden), so this scrollable
   settings panel is the only place a footer can live and still be reached. */
.app-footer {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  margin: 0;
  font-family: var(--font-mono);
  font-size: 13px;
  color: var(--muted);
}

.app-footer__icon {
  width: 14px;
  height: 14px;
  flex-shrink: 0;
}

/* Tighter than the .screen's 1.5rem gap between major sections — these two
   rows read as one grouped settings block, not separate sections. */
.toggle-group {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.toggle-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 1rem 1.25rem;
  cursor: pointer;
}

.toggle-label {
  font-size: 1rem;
  font-weight: 700;
  color: var(--fg);
}

/* Volume lives in the same card as the Sound cues toggle (not a card of
   its own) — the wrapper carries the shared border/radius, and the inner
   .toggle-row drops its own so the two sections read as one card split by
   a hairline, not two stacked boxes. */
.sound-settings {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
}
.sound-settings .toggle-row {
  border: none;
  border-radius: 0;
}

/* Mirrors .breadcrumb's own fixed top-left positioning (z-index), flipped
   to the right edge, so the two sit on the same row without either having
   to know about the other's width. The top offset is pulled up slightly
   from .breadcrumb's 2.5rem so this button's vertical center lines up with
   the breadcrumb text's center rather than their top edges — the button
   is taller than a line of text. */
.install-pill-anchor {
  position: fixed;
  top: calc(2.5rem - 14px);
  right: 1.5rem;
  z-index: 10;
}

@media (min-width: 696px) {
  .install-pill-anchor {
    right: 2.5rem;
  }
}

/* Reuses .icon-btn (the same style as the run screen's Settings/Reset
   buttons) instead of a bespoke circular pill, sized down to match this
   button's smaller footprint in the breadcrumb row. */
.install-pill {
  width: 2.5rem; /* 40px */
  height: 2.5rem;
}

.install-pill .icon {
  width: 1.125rem;
  height: 1.125rem;
  flex-shrink: 0;
}

/* iOS only — stays visually "pressed" while its tooltip is open. */
.install-pill[aria-expanded='true'] {
  background-color: rgba(255, 255, 255, 0.08);
}

/* iOS only — tapping the button toggles .install-pill-tooltip instead of
   triggering an install (there's no API to call), so it's positioned
   relative to that same anchor, not floating independently. */
.install-pill-tooltip {
  position: absolute;
  top: calc(100% + 0.5rem); /* 8px below the button */
  right: 0;
  width: max-content;
  max-width: 220px;
  padding: 0.75rem 1rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg-raised);
  color: var(--white);
  font-family: var(--font-mono);
  font-size: 0.8125rem; /* 13px */
  line-height: 1.4;
}

.install-pill-tooltip strong {
  color: var(--fg);
}

/* Hidden while sound cues are off — volume is meaningless with nothing to
   play. */
.volume-row {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 0.25rem 1.25rem 1rem;
  border-top: 1px solid var(--border);
}
.volume-row[hidden] { display: none; }

.volume-value {
  flex-shrink: 0;
  min-width: 3.5ch;
  text-align: right;
  font-family: var(--font-mono);
  font-size: 0.875rem;
  font-variant-numeric: tabular-nums;
  color: var(--muted);
}

/* Custom range styling: a thin track (the native one is inconsistent
   across browsers) with a bright thumb sized to the mobile tap-target
   minimum even though it reads much smaller visually — the generous
   hit-slop matters more than the thumb looking chunky. The 25%-step
   datalist gives discrete stops rather than a fully continuous drag. */
.volume-slider {
  appearance: none;
  -webkit-appearance: none;
  flex: 1;
  min-height: 3rem; /* tap-target height, not track height */
  background: transparent;
  cursor: pointer;
  touch-action: manipulation;
}
/* The filled portion left of the thumb — Chromium/Safari have no native
   progress pseudo-element, so it's faked with a second, holofoil
   background layer sized to --volume-fill (a percentage set from JS on
   init/input) and left-aligned with no-repeat; the plain border-color
   layer underneath shows through for the unfilled remainder. Firefox gets
   the same look via its actual ::-moz-range-progress fill. */
.volume-slider::-webkit-slider-runnable-track {
  height: 0.25rem;
  border-radius: 999px;
  background-image: var(--holofoil-btn), linear-gradient(var(--border), var(--border));
  background-size: var(--volume-fill, 0%) 100%, 100% 100%;
  background-repeat: no-repeat;
}
.volume-slider::-moz-range-track {
  height: 0.25rem;
  border-radius: 999px;
  background: var(--border);
}
.volume-slider::-moz-range-progress {
  height: 0.25rem;
  border-radius: 999px;
  background-image: var(--holofoil-btn);
}
.volume-slider::-webkit-slider-thumb {
  appearance: none;
  -webkit-appearance: none;
  width: 1.25rem;
  height: 1.25rem;
  margin-top: -0.5rem;
  border-radius: 50%;
  background: var(--fg);
  cursor: pointer;
  transition: transform 0.1s ease;
}
.volume-slider::-moz-range-thumb {
  width: 1.25rem;
  height: 1.25rem;
  border: none;
  border-radius: 50%;
  background: var(--fg);
  cursor: pointer;
  transition: transform 0.1s ease;
}
.volume-slider:active::-webkit-slider-thumb { transform: scale(1.15); }
.volume-slider:active::-moz-range-thumb { transform: scale(1.15); }

/* Switch, not a toggle button: gray track when off, filled with the same
   holofoil-btn recipe as our other buttons when on, and the more-saturated
   "active" gradient variant while being pressed — same state pattern as
   .btn-primary / .icon-btn-primary, just applied to a track+thumb instead
   of a filled rect. */
.switch {
  appearance: none;
  -webkit-appearance: none;
  position: relative;
  flex-shrink: 0;
  width: 3.5rem;
  height: 2rem;
  padding: 0;
  border: 2px solid var(--muted);
  border-radius: 999px;
  background: transparent;
  cursor: pointer;
  transition: border-color 0.15s ease, background-image 0.15s ease;
}

.switch[aria-checked="true"] {
  border-color: transparent;
  background-image: var(--holofoil-btn), linear-gradient(var(--holofoil-btn-base), var(--holofoil-btn-base));
}

.switch:active {
  border-color: transparent;
  background-image: var(--holofoil-btn-active), linear-gradient(var(--holofoil-btn-active-base), var(--holofoil-btn-active-base));
}

.switch-thumb {
  position: absolute;
  top: 2px;
  left: 2px;
  width: 1.5rem;
  height: 1.5rem;
  border-radius: 50%;
  background: var(--muted);
  transition: transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1), background-color 0.15s ease;
}

.switch[aria-checked="true"] .switch-thumb {
  background: #0A0A0A;
  transform: translateX(1.5rem);
}

/* A manually-positioned label beats a native <legend>: fieldset border-radius
   makes browsers render the legend's border "cutout" inconsistently (a stray
   line through the text). This patches the border with a bg-colored backdrop
   instead, which is reliable everywhere and lets us size/weight it to read
   clearly instead of tiny uppercase letter-spaced text. */
.group-label {
  position: absolute;
  top: 0;
  /* Offset left by the label's own padding below, so the *text* lines up
     with .toggle-label's text (1.25rem, no padding of its own) — matching
     this element's box edge to 1.25rem instead left the text itself
     sitting visibly further right, since the padding exists to cut a
     notch in the border, not to indent the text. */
  left: calc(1.25rem - 0.6rem);
  transform: translateY(-50%);
  background: var(--bg);
  padding: 0 0.6rem;
  font-size: 1rem;
  font-weight: 700;
  color: var(--fg);
}

/* One row, equal-width segments filling the full container — not
   content-sized chips wrapping/centering, so a label changing width (e.g.
   the Custom chip showing an entered value) never reflows its neighbors. */
.presets {
  display: flex;
  gap: 0.5rem;
}

.chip {
  appearance: none;
  -webkit-appearance: none;
  flex: 1;
  min-width: 0;
  min-height: 3rem; /* 48px — meets the 44pt/48dp mobile tap-target minimum */
  padding: 0.6rem 0.25rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  text-align: center;
  border-radius: var(--control-radius);
  border: 1px solid var(--border);
  background: transparent;
  color: var(--white);
  font-family: var(--font-mono);
  font-size: 1rem; /* 16px */
  font-variant-numeric: tabular-nums;
  cursor: pointer;
  transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}

/* The infinite-rounds chip uses a Lucide icon instead of the "∞" glyph,
   which rendered tiny/cramped in the mono font at chip scale. */
.chip-icon {
  display: flex;
  align-items: center;
  justify-content: center;
}
.chip-icon .icon {
  width: 1.125rem;
  height: 1.125rem;
}
.chip:hover { border-color: var(--fg); }
.chip:active { transform: scale(0.95); }
.chip[aria-pressed="true"] {
  background: var(--fg);
  border-color: var(--fg);
  color: #0A0A0A;
  font-weight: 700;
}

/* display:contents so the wrapper itself doesn't become a flex item (and
   doesn't add its own sizing/gap) — the button/input inside take its place
   in the .presets row directly, swapped via [hidden] so only one shows. */
.chip-custom-wrap { display: contents; }

/* While a field's Custom stepper panel is open, the whole presets row is
   just noise competing with the panel below — hide it entirely. Its own
   Done control lives inline in the panel instead (see .custom-done-btn). */
.presets.custom-active {
  display: none;
}

/* Press-and-hold stepper panel "Custom" reveals in place of typing an
   mm:ss value — tap-to-step (with auto-repeat on hold) suits mobile/
   one-handed use far better than popping a keyboard. No margin-top: it
   takes the exact spot the (now display:none) presets row occupied, so
   the group's height doesn't shift when Custom opens. */
.custom-panel {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.custom-panel[hidden] { display: none; }

/* The stepper and the Done button are one visual cluster, centered
   together — not spread to the row's far edges, which on anything wider
   than a phone reads as the controls drifting off to one side. */
.stepper-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1.25rem;
}

/* Horizontal, not stacked: a thumb reaching for a vertically-stacked +
   button has to pass right over the value to get there, obscuring the
   very number it's changing. Side-by-side −/+ keeps the value in the
   clear no matter which button a thumb is on. */
.stepper-controls {
  display: flex;
  align-items: center;
  gap: 1.25rem;
}

.stepper-display {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.125rem;
  min-width: 4ch;
}

/* Interval/Rest's value is also a button — tapping it swaps in
   .stepper-value-input below for anyone who'd rather type an exact mm:ss
   than tap to it. The dashed underline on the value is the only hint it's
   interactive, so it doesn't compete visually with the −/+ steppers. */
.stepper-display-btn {
  appearance: none;
  -webkit-appearance: none;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.125rem;
  min-width: 4ch;
  border: none;
  background: transparent;
  padding: 0;
  cursor: pointer;
}
.stepper-display-btn[hidden] { display: none; }
.stepper-display-btn .stepper-value {
  border-bottom: 1px dashed var(--border);
  padding-bottom: 0.0625rem;
  transition: border-color 0.15s ease;
}
.stepper-display-btn:hover .stepper-value,
.stepper-display-btn:focus-visible .stepper-value {
  border-color: var(--fg);
}

.stepper-value-input {
  appearance: none;
  -webkit-appearance: none;
  width: 5.5rem;
  min-height: 3rem; /* matches .stepper-btn's tap target */
  padding: 0.25rem;
  border-radius: var(--control-radius);
  border: 1px solid var(--fg);
  background: transparent;
  color: var(--white);
  font-family: var(--font-mono);
  font-size: 1.5rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  text-align: center;
}

.stepper-value {
  font-family: var(--font-mono);
  font-size: 1.5rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  text-align: center;
  color: var(--white);
}

.stepper-label {
  font-size: 0.6875rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted);
}

.stepper-btn {
  appearance: none;
  -webkit-appearance: none;
  width: 3rem; /* 48px — meets the 44pt/48dp mobile tap-target minimum */
  height: 3rem;
  border-radius: var(--control-radius);
  border: 1px solid var(--border);
  background: transparent;
  color: var(--fg);
  font-family: var(--font-mono);
  font-size: 1.25rem;
  line-height: 1;
  cursor: pointer;
  user-select: none;
  touch-action: manipulation;
  transition: background-color 0.15s ease, border-color 0.15s ease, transform 0.1s ease;
}

.stepper-btn:hover { border-color: var(--fg); }
.stepper-btn:active {
  transform: scale(0.92);
  background: var(--fg);
  color: #0A0A0A;
}

/* Filled, not outlined, so it reads as the confirm action at a glance next
   to the outlined −/+ steppers it shares a row with. */
.custom-done-btn {
  appearance: none;
  -webkit-appearance: none;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 3rem; /* 48px — matches .stepper-btn's tap target */
  height: 3rem;
  border: none;
  border-radius: var(--control-radius);
  background: var(--fg);
  color: #0A0A0A;
  cursor: pointer;
  transition: filter 0.15s ease, transform 0.1s ease;
}
.custom-done-btn .icon { width: 1.25rem; height: 1.25rem; }
.custom-done-btn:hover { filter: brightness(1.08); }
.custom-done-btn:active { transform: scale(0.92); }

/* - - - - - - - - - - - - - - - - - - - - *\
BUTTONS
\* - - - - - - - - - - - - - - - - - - - - */
/* Hidden filter defs (see index.html) — zero footprint so they don't affect layout. */
.btn-blob-defs {
  position: absolute;
  width: 0;
  height: 0;
}

.btn {
  appearance: none;
  -webkit-appearance: none;
  font-family: var(--font-mono);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  border-radius: var(--radius);
  border: none;
  cursor: pointer;
  transition: background-image 0.2s ease-in-out, box-shadow 0.2s ease-in-out, transform 0.1s cubic-bezier(0.34,1.56,0.64,1);
}

.btn-huge {
  width: 100%;
  min-height: 3rem; /* 48px, same on every viewport */
  font-size: 1.5rem; /* 24px */
}

/* Same gradient + state recipe as the "Email Adam" button on adamruf.com. */
.btn-primary {
  position: relative;
  overflow: hidden;
  color: #0A0A0A;
  background-image: var(--holofoil-btn), linear-gradient(var(--holofoil-btn-base), var(--holofoil-btn-base));
  box-shadow: var(--holofoil-btn-shadow);
  transition: filter 0.15s ease, background-image 0.2s ease-in-out, box-shadow 0.2s ease-in-out, transform 0.1s cubic-bezier(0.34,1.56,0.64,1);
}
/* Hover just brightens the existing gradient rather than swapping to a
   separate hover-specific one — subtler, and one fewer gradient to keep
   in sync with the base/active colors. */
.btn-primary:hover {
  filter: brightness(1.08);
}
/* Pressed state blooms out from the actual touch point (like heat-sensing
   fabric) instead of a flat gradient swap — same color stops as
   --holofoil-btn-active, run through the shared #btn-blob SVG filter (see
   index.html) so the bloom reads as an organic blob rather than a clean
   circle. Centered on --press-x/--press-y (set via JS on pointerdown;
   defaults to center for keyboard activation). */
.btn-primary::after,
.icon-btn-primary::after {
  content: '';
  position: absolute;
  inset: -25%;
  /* Sits above the button's own background but below its (non-positioned)
     label/icon content — without this it paints over the text. */
  z-index: -1;
  background: radial-gradient(circle at var(--press-x, 50%) var(--press-y, 50%), #AEFF00 0%, #EEFF00 45%, #A2FFC6 75%, rgba(162, 255, 198, 0) 90%);
  filter: url(#btn-blob);
  opacity: 0;
  transition: opacity 0.15s ease-out;
  pointer-events: none;
}
.btn-primary:active::after,
.icon-btn-primary:active::after {
  opacity: 1;
}
.btn-primary:active {
  box-shadow: none;
  transform: scale(0.95);
}

/* - - - - - - - - - - - - - - - - - - - - *\
RUN SCREEN
\* - - - - - - - - - - - - - - - - - - - - */
#run-screen {
  align-items: center;
  text-align: center;
}

/* Fills the leftover vertical space (everything above run-controls, which
   stays in normal flow and lands at the bottom once this has claimed the
   rest) and centers the ring+dots as one group within it — not pinned to
   the top, not splitting space unevenly the way a lone margin-top: auto on
   run-controls did. Scrolls on its own (min-height: 0 + overflow-y: auto)
   rather than #run-screen as a whole, so a short window (e.g. a resizable
   installed-app window dragged down to near-square) shrinks/scrolls the
   ring instead of scrolling .run-controls along with it — Pause/Settings/
   Reset (see .run-controls below, flex-shrink: 0) always stay on-screen,
   the same way Done always does on the setup screen. The vmin-based ring/
   time-display sizing below is still the primary fix, keeping things from
   needing to overflow in the first place on most window shapes; this is
   the fallback for when it's not enough. */
.run-content {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  /* Plain "center" on an overflowing flex item is a known trap: the
     browser keeps the item's geometric center aligned with the
     container's, which shears equal amounts off *both* the top and
     bottom — and depending on how the resulting scroll range gets
     computed, part of each end can end up permanently unreachable even by
     scrolling. "safe" is the standard fix: center when everything fits,
     but fall back to start-alignment the moment it doesn't, so the ring
     anchors to the top and only the bottom (round dots/text) needs a
     scroll — one predictable, fully-reachable crop instead of two
     partial, possibly-unreachable ones. */
  justify-content: safe center;
  gap: 1.5rem;
  width: 100%;
}

/* Scaled to stay in lockstep with .time-display's own
   clamp(3rem, 15vmin, 5rem) — not an independent vmin formula with its own
   cap, which is what let the two drift out of proportion at some widths
   (the font already at max size while the ring was still capped smaller,
   or vice versa, pinching clearance). "59:59" (the widest possible value)
   measures to a consistent 3.0596x multiple of font-size across sizes (no
   meaningful intercept), so textWidth = 3.0596 * fontSize. Solving
   ring_inner_diameter (0.75 * this width, from the SVG geometry) =
   textWidth + 48 (a consistent 24px clearance per side) against that
   gives ringWidth = 4.0795 * fontSize + 64 — fontSize's floor/ceiling (48,
   80) and its 15vmin fluid middle plug straight in, giving this clamp's
   three stops: 264px at the 3rem floor, 392px at the 5rem ceiling, ~61.19vmin
   + 64px in between (that fluid term is pure algebra off the 3.0596/4.0795
   constants above, so it's unchanged by whatever the floor/ceiling literals
   are). Clearance now holds at a near-constant 24px+ per side across every
   viewport, by construction, not by coincidence. Supersedes the old mobile-
   cap-plus-desktop-override split; one rule now covers every viewport. Both
   bounds are 8px-grid multiples (264 = 8*33, 392 = 8*49), scaled down from
   the original 292/423 to buy back vertical space for the breadcrumb
   clearance above. vmin, not vw: this app ships as an installable desktop
   PWA too, where the window can be resized down to something short/square —
   vw alone chased width and ignored height entirely, so a short window
   could size the ring/text past what actually fit vertically. vmin (the
   smaller of vw/vh) tracks whichever dimension is actually tightest. */
.ring-wrap {
  position: relative;
  width: clamp(264px, calc(64px + 61.19vmin), 392px);
  aspect-ratio: 1;
  margin: 0.5rem auto;
}

/* Dark glass disc behind the ring, sized to end exactly at the Rest ring's
   outer edge (r=126 + half its 8px stroke-width = 130, out of the SVG's
   136-radius viewBox — 130/136 = 95.588%). Same recipe as adamruf.com's
   ghibli-ranking .card *hover* state (not its resting state) — brighter
   border/glow than a plain glass card, since this sits permanently rather
   than needing a hover to "activate" it. z-index: -1 keeps it behind the
   ring/time-display/round-indicator, which are all later in source order
   (or themselves positioned) and would otherwise paint on top of a
   positioned ::before by default. */
.ring-wrap::before {
  content: '';
  position: absolute;
  inset: calc((100% - 95.588%) / 2);
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.08);
  box-shadow: 0 0 20px rgba(255, 255, 255, 0.15);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  z-index: -1;
}

/* scaleX(-1) must come before the rotate (CSS applies the rightmost
   function to the SVG's local coordinates first) — otherwise it mirrors
   the already-rotated ring and knocks its 12 o'clock start point off
   center instead of just reversing its sweep direction. A circle's path
   direction is fixed clockwise in local SVG space (how stroke-dashoffset
   math in app.js is written), so without this flip the drain ring's
   trailing edge recedes counter-clockwise instead of the expected
   clockwise sweep. */
.progress-ring { width: 100%; height: 100%; transform: scaleX(-1) rotate(-90deg); }

/* Faded out (not removed from layout) whenever Rest genuinely isn't coming
   up this round — see updateRestRingRelevance() in app.js. */
#rest-ring-group { transition: opacity 0.2s ease; }

/* Work (inner) is heavier/bolder, Rest (outer) is lighter — now the only
   signal for which ring is which, since both share the same accent color
   (standardized rather than giving Rest its own blue/purple hue). Width +
   nested position carries the distinction; still works for colorblind
   users, unlike a color-only cue would. */
.ring-track {
  fill: none;
  stroke: rgba(255, 255, 255, 0.08);
}

.ring-fill {
  fill: none;
  stroke-linecap: round;
  opacity: 1;
  /* Short, linear, matched to the 200ms render-tick cadence — a longer
     transition (the original 1s) kept easing toward a stale target and
     visibly crawled backward at each phase reset. Opacity rides the same
     transition so the idle ring's dim-down (see app.js) isn't an abrupt cut. */
  transition: stroke-dashoffset 0.2s linear, opacity 0.2s ease;
}

.ring-track-work,
.ring-fill-work {
  stroke-width: 12;
  /* Matches RING_CIRCUMFERENCE_WORK in app.js (2 * PI * 108) to the exact
     float, not just a rounded-off decimal — a mismatch between this and
     the JS-set dashoffset is what used to leave a stray sliver of stroke
     visible at 0% progress (a round-linecap rendering quirk) instead of a
     truly empty ring. */
  stroke-dasharray: 678.5840131753953;
}
.ring-fill-work {
  stroke: url(#ring-gradient);
  stroke-dashoffset: 0;
}

.ring-track-rest,
.ring-fill-rest {
  stroke-width: 8; /* multiple of the 2px subgrid, matches Work's 12px */
  stroke-dasharray: 791.6813487046279; /* 2 * PI * 126 — leaves an 8px gap to Work's outer edge, see .ring-fill-work above */
}

/* Invisible at rest — only ever seen mid-pulse (see .pulse below), fired
   once per lead-in beat from app.js. transform-box: fill-box scales it
   around its own center regardless of where it sits in the SVG, rather
   than the default SVG viewport origin. Base r=4 (8px diameter) scaled up
   to 1.5x at peak = 12px — capped to match the work ring's own
   stroke-width (12), so the pulse never reads as thicker than the ring
   it's sitting on. */
.ring-lead-in-dot {
  fill: var(--fg);
  opacity: 0;
  transform-box: fill-box;
  transform-origin: center;
}
.ring-lead-in-dot.pulse {
  animation: ring-lead-in-dot-pulse 0.5s ease-out;
}
@keyframes ring-lead-in-dot-pulse {
  0% { opacity: 1; transform: scale(1); }
  70% { opacity: 0.8; transform: scale(1.5); }
  100% { opacity: 0; transform: scale(1.5); }
}
@media (prefers-reduced-motion: reduce) {
  .ring-lead-in-dot.pulse { animation: none; }
}
.ring-fill-rest {
  stroke: url(#ring-gradient);
  stroke-dashoffset: 0;
}

/* No more .ring-center wrapper — the phase label moved into the pause
   button (.pause-btn-label), so the time display is the ring's only
   content now and centers itself without needing a flex column + gap. */
.time-display {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: clamp(3rem, 15vmin, 5rem);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  line-height: 1;
  user-select: none;
  -webkit-user-select: none;
}

@keyframes time-breathe {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.55; }
}

.time-display.paused,
.ring-fill.paused,
.round-indicator.paused {
  animation: time-breathe 2.2s ease-in-out infinite;
}

@media (prefers-reduced-motion: reduce) {
  .time-display.paused,
  .ring-fill.paused,
  .round-indicator.paused { animation: none; }
  .ring-fill { transition: none; }
}

/* Sits inside .ring-wrap, below .time-display, without disturbing its
   centering (.time-display is still position: absolute; inset: 0) — this
   is independently positioned against the same box instead of flowing
   underneath it. top is tuned to clear the time text at every size in its
   clamp() (see .time-display) while staying inside the work ring's inner
   edge, not against .ring-wrap's own height, which is fixed regardless of
   .time-display's actual rendered height at a given viewport. */
.round-indicator {
  position: absolute;
  left: 50%;
  top: 68%;
  transform: translate(-50%, -50%);
  display: flex;
  align-items: center;
  gap: 0.375rem; /* 6px */
}

.round-indicator-label {
  font-family: var(--font-mono);
  font-size: 0.9375rem;
  font-variant-numeric: tabular-nums;
  color: var(--muted);
}

.round-indicator-infinity {
  width: 1rem;
  height: 1rem;
  color: var(--muted);
}

.round-dot {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.16); /* 2x .ring-track's 0.08 */
  transition: background-color 0.2s ease;
}

.round-dot.filled {
  background: var(--white);
}

/* Three flat states, no animation: resting gray (default), a middle-ground
   active color for the round currently running (comes after .filled in the
   cascade, since the active round is also "filled so far" — this is what
   should win), and white once it's actually done. A static color swap reads
   clearly enough on its own; pulsing it on top just made it compete with
   the ring's own progress animation for attention. */
.round-dot.active {
  background: rgba(255, 255, 255, 0.5);
}

/* Rest ring — wraps a round dot that's followed by a rest (every round
   except the last, which has nothing after it). Gray/empty until that
   round's rest starts, then fills to the rest accent color and stays that
   way, so the row reads as "N work rounds, N-1 rests between them" instead
   of recoloring the dots themselves (which implied one rest too many). */
.round-dot-ring {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  border: 2px solid rgba(255, 255, 255, 0.16); /* matches .round-dot's resting gray */
  flex-shrink: 0;
  transition: border-color 0.3s ease;
}

.round-dot-ring.filled {
  border-color: var(--white);
}

/* Same three-state treatment as .round-dot.active above. */
.round-dot-ring.active {
  border-color: rgba(255, 255, 255, 0.5);
}

.run-controls {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  /* #run-screen centers its children (align-items: center), so without an
     explicit width this row shrink-wraps to its buttons' content size —
     leaving no extra space for the pause button's flex:1 to grow into. */
  width: 100%;
  /* Sibling of .run-content, which does the scrolling (see above) — this
     stays fixed size rather than shrinking to make room for it, the same
     way .done-group never shrinks on the setup screen. */
  flex-shrink: 0;
}

/* Settings and reset stay fixed-size squares; pause/resume (below) fills
   the remaining width instead of matching them, making it the clear
   primary action in the row rather than just another same-sized icon. */
.run-controls .icon-btn {
  width: 3rem;
  height: 3rem; /* 48px, same on every viewport — matches the setup screen's Done button (.btn-huge) */
  flex-shrink: 0;
}

.run-controls .icon-btn-primary {
  flex: 1;
  width: auto;
  height: 3rem; /* 48px, fixed — same strict height as the square icon
    buttons either side of it, never taller. The "Start X session" label
    (see .pause-btn-label) truncates with an ellipsis instead of wrapping,
    so this never needs to grow to fit it. */
  padding: 0 1rem;
}

/* Pause/resume is still the primary action in this row — filled with the
   same gradient + state recipe as the "Email Adam" button on adamruf.com
   (rest/hover/active each swap gradient, shadow, and scale). Height,
   radius, and label size now match the setup screen's Done button
   (.btn/.btn-huge) so the two primary CTAs feel like the same button. */
.icon-btn-primary {
  border: none;
  border-radius: var(--radius);
  background-image: var(--holofoil-btn), linear-gradient(var(--holofoil-btn-base), var(--holofoil-btn-base));
  color: #0A0A0A;
  box-shadow: var(--holofoil-btn-shadow);
  transition: filter 0.15s ease, background-image 0.2s ease-in-out, box-shadow 0.2s ease-in-out, transform 0.1s cubic-bezier(0.34,1.56,0.64,1);
}

/* Text button now (no icon) — same type treatment as the setup screen's
   Done button (.btn/.btn-huge) rather than a smaller icon-adjacent label. */
.pause-btn-label {
  display: block;
  max-width: 100%;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  font-family: var(--font-mono);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  font-size: 1.5rem; /* 24px */
}
/* The base .icon-btn hover/active/focus rule turns secondary icons green —
   override it back to black here so the primary (filled) button's icon
   doesn't pick up that color swap. */
.icon-btn-primary:hover,
.icon-btn-primary:active,
.icon-btn-primary:focus-visible {
  color: #0A0A0A;
}
/* Same subtle brighten as .btn-primary:hover — works for both work and
   rest since it brightens whatever gradient is already applied, no
   phase-specific hover variant needed. */
.icon-btn-primary:hover {
  filter: brightness(1.08);
}
/* Same touch-centered blob bloom as .btn-primary:active (see comment there
   and the shared ::after rule above). */
.icon-btn-primary {
  position: relative;
  overflow: hidden;
}
.icon-btn-primary:active {
  box-shadow: none;
  transform: scale(0.95);
}
/* - - - - - - - - - - - - - - - - - - - - *\
RESPONSIVE
\* - - - - - - - - - - - - - - - - - - - - */
@media (min-width: 696px) {
  /* The base #app padding (see above) already clears both fades with room
     to spare at every width, so no desktop-specific top/bottom override is
     needed here anymore — just the roomier inter-section gap. */
  .screen { gap: 2.25rem; }
  /* .ring-wrap no longer needs a size override here — its own clamp()
     already reaches and holds 420px well before this breakpoint starts. */
}

/* - - - - - - - - - - - - - - - - - - - - *\
HOLOFOIL — matches adamruf.com's gradient. Declared last so it wins over
earlier same-specificity color rules (.wordmark, .time-display) by source
order.
\* - - - - - - - - - - - - - - - - - - - - */
.holofoil-text {
  background-image: var(--holofoil), var(--holofoil-base);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
}
