/* Fonts ship with the app (SIL Open Font License, see fonts/OFL-*.txt; Permanent Marker: Apache), so it looks right
   offline from the first launch and makes no requests to a font service. Both are
   variable fonts covering the weight ranges below. */
/* Orbitron is the original font file, unmodified (its licence reserves the name for unchanged copies). */
@font-face{
  font-family:'Orbitron'; font-style:normal; font-weight:400 900; font-display:swap;
  src:url(fonts/orbitron.ttf) format('truetype');
}
@font-face{
  font-family:'Space Grotesk'; font-style:normal; font-weight:400 700; font-display:swap;
  src:url(fonts/space-grotesk-latin-ext.woff2) format('woff2');
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face{
  font-family:'Caveat'; font-style:normal; font-weight:700; font-display:swap;
  src:url(fonts/caveat-latin.woff2) format('woff2');
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* Permanent Marker is under the Apache License 2.0 (fonts/LICENSE-PermanentMarker.txt). */
@font-face{
  font-family:'Permanent Marker'; font-style:normal; font-weight:400; font-display:swap;
  src:url(fonts/permanent-marker-latin.woff2) format('woff2');
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face{
  font-family:'Space Grotesk'; font-style:normal; font-weight:400 700; font-display:swap;
  src:url(fonts/space-grotesk-latin.woff2) format('woff2');
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

:root{
  --bg:#0a0d12;
  --bg-panel:#10141b;
  --text:#f5f7fa;
  --text-dim:#8b94a3;
  --accent:#ffb454;
  --accent2:#5ec9f1;
  --divider:rgba(255,255,255,0.09);
  --shadow:rgba(0,0,0,0.4);
  /* Set from JS once the fonts load (see measureTime in app.js): width of the widest
     "HH:MM" per 1em of font size, and the time row's height per 1em. */
  --time-ratio:3.6;
  --cap:0.73;
}
@media (prefers-color-scheme: light){
  :root{
    --bg:#f4f2ec;
    --bg-panel:#ffffff;
    --text:#14181f;
    --text-dim:#4b5260;
    --accent:#c2740f;
    --accent2:#0f7ea8;
    --divider:rgba(0,0,0,0.08);
    --shadow:rgba(0,0,0,0.12);
  }
}
:root{ color-scheme:dark light; --fill-green:#4ad08a; --fill-pink:#ff7aa8; --fill-purple:#b294ff; }
/* The accents as text and small marks: on the light background they need to be a little
   darker to read (4.5:1). */
:root{ --accent-ink:#ffb454; --accent2-ink:#5ec9f1; }
@media (prefers-color-scheme: light){ :root{ --accent-ink:#9a5800; --accent2-ink:#0a6688; } }
:root[data-theme="dark"]{ --accent-ink:#ffb454; --accent2-ink:#5ec9f1; }
:root[data-theme="light"]{ --accent-ink:#9a5800; --accent2-ink:#0a6688; }
@media (prefers-color-scheme: light){ :root{ --fill-green:#1e9a5c; --fill-pink:#d23f74; --fill-purple:#7a57d6; } }
:root[data-theme="dark"]{ --fill-green:#4ad08a; --fill-pink:#ff7aa8; --fill-purple:#b294ff; }
:root[data-theme="light"]{ --fill-green:#1e9a5c; --fill-pink:#d23f74; --fill-purple:#7a57d6; }
:root[data-theme="dark"]{
  color-scheme:dark;
  --bg:#0a0d12; --bg-panel:#10141b; --text:#f5f7fa; --text-dim:#8b94a3;
  --accent:#ffb454; --accent2:#5ec9f1; --divider:rgba(255,255,255,0.09); --shadow:rgba(0,0,0,0.4);
}
:root[data-theme="light"]{
  color-scheme:light;
  --bg:#f4f2ec; --bg-panel:#ffffff; --text:#14181f; --text-dim:#4b5260;
  --accent:#c2740f; --accent2:#0f7ea8; --divider:rgba(0,0,0,0.08); --shadow:rgba(0,0,0,0.12);
}

*{box-sizing:border-box;}
[hidden]{display:none !important;}
/* The background is the page's own (html), so the screen fill (z-index -1) can sit between
   it and everything else. */
html{ background:var(--bg); }
/* Sky tint (Settings > Show): app.js sets --sky-bg on the page (only its background, never a
   text colour) from the time of day; not under Windows contrast themes. */
@media (forced-colors:none){
  html[data-sky]{ background:var(--sky-bg); }
}
html,body{
  margin:0; padding:0; height:100%; width:100%;
  color:var(--text);
  overflow:hidden;
  font-family:'Space Grotesk',system-ui,sans-serif;
  -webkit-font-smoothing:antialiased;
}
button{ font:inherit; color:inherit; }

/* Installed app with the title bar hidden (window-controls-overlay): this strip stands in
   for the title bar so the window can still be dragged. The env() values only exist in
   that mode; everywhere else the strip has zero height. Only the strip is draggable:
   a drag region swallows mouse events, so making the whole clock draggable would break
   hover on the tools. */
.titlebar{
  position:fixed;
  left:env(titlebar-area-x, 0); top:env(titlebar-area-y, 0);
  width:env(titlebar-area-width, 100%); height:env(titlebar-area-height, 0px);
  app-region:drag; -webkit-app-region:drag;
}

/* Layout model. The old version gave the time row a fixed 65% of the height; the digits
   are almost always width-bound, so that row carried empty bands above and below them,
   and the weather cells were fixed-width columns with their own dead space.
   Now: the time row is exactly as tall as the digits (sized from .app's width/height),
   the weather band is scaled by JS (fitBand in app.js) to the largest size that fits the
   space left over, and whatever space remains is shared evenly above, between and below
   the rows (space-evenly), so it reads as margin rather than as holes. */
.app{
  height:100vh; width:100vw;
  padding:
    calc(env(titlebar-area-height, 0px) + clamp(0.3rem, 1.5vh, 1rem))
    clamp(0.6rem, 2.6vw, 2rem)
    clamp(0.3rem, 1.5vh, 1rem);
  container-type:size; container-name:app;
}
.primary{
  height:100%; width:100%;
  display:grid;
  grid-template-columns:minmax(0,1fr);
  /* Implicit rows only: an explicit empty track (no timer running) would count as one
     more row in space-evenly and leave a double gap at the bottom. */
  grid-auto-rows:auto;
  align-content:space-evenly;
}
/* --tsize: the digits fill the width (cqw / ratio) unless that would make them taller
   than their share of the height (cqh / cap), whichever is smaller. --tfit (set by
   fitLayout in app.js) stays 1 unless the weather and timers need some of that share. */
/* --tw / --th: the shares of the width and height the digits may take. */
.primary{ --tsize:calc(min(calc(var(--tw) / (var(--time-ratio) + 2 * var(--ring-x, 0))), calc(var(--th) * var(--th-k, 1) / (var(--cap) + 2 * var(--ring-y, 0)))) * var(--tfit, 1) * var(--size-k, 1)); }
/* Snug (Settings > Show > Spacing): the clock may take more of the height, and the rows sit
   close together in the middle instead of sharing out the spare space between them. */
:root[data-spacing="snug"] .primary{ --th-k:1.2; align-content:center; row-gap:1.5cqh; }
:root[data-layout="row"] .primary{ --tw:97cqw; --th:52cqh; }
:root[data-layout="stack"] .primary{ --tw:95cqw; --th:32cqh; }
/* Stacked digits are tall and narrow, so they get a bigger share of the height. */
:root[data-clock="stack"][data-layout="row"] .primary{ --th:62cqh; }
:root[data-clock="stack"][data-layout="stack"] .primary{ --th:44cqh; }
/* The clock alone (no date, weather or timers showing) may fill nearly the whole height, so
   a short, wide window becomes a single neat row; with just a date line under it, most of it. */
:root[data-solo="clock"][data-layout][data-clock] .primary{ --th:88cqh; }
:root[data-solo="date"][data-layout="row"][data-clock] .primary{ --th:72cqh; }
:root[data-solo="date"][data-layout="stack"][data-clock] .primary{ --th:56cqh; }
/* --ring-x / --ring-y: the race ring's margins around the digits, in em, set by app.js while
   the ring shows (0 otherwise), so the digits shrink just enough to make room for it. */

/* ---------- time ---------- */
.time{
  justify-self:center; position:relative;
  display:flex; align-items:center; justify-content:center;
  font-family:'Orbitron',sans-serif;
  font-weight:900;
  font-size:var(--tsize);
  line-height:1;
  letter-spacing:0.01em;
  color:var(--accent);
  font-variant-numeric:tabular-nums;
  white-space:nowrap;
}
/* Trim the line box to the digits themselves, so the row's height is the digits' height
   with no built-in space above the caps or below the baseline. The font's unused room
   (for letters that dip below the line) is clipped too: invisible, but it used to reach
   past the bottom of very short windows. */
.time .hh, .time .mm{ text-box:trim-both cap alphabetic; overflow:clip; overflow-clip-margin:2px; }
@supports not (text-box: trim-both cap alphabetic){
  .time .hh, .time .mm{ line-height:0.76; }
}
/* Off-screen copy at a fixed size, used only to measure --time-ratio / --cap. */
.time.measure{ position:absolute; left:-10000px; top:0; visibility:hidden; font-size:100px; }
.time.measure .ring{ display:none; }

/* Colon is a small widget, not a glyph: dots with the live seconds between them, and
   (in 12h mode) the am/pm tag below, so neither costs horizontal space. In 12h mode it
   is taller than the digits and sets the row height (--cap is measured to match). */
.colon{
  display:flex; flex-direction:column; align-items:center; justify-content:space-between;
  height:0.56em; width:0.42em;
  margin:0 0.05em;
}
.colon.has-ampm{ height:0.9em; }
.colon .dot{
  display:block; width:0.15em; height:0.15em; border-radius:15%;
  background:var(--accent); flex-shrink:0;
  animation:blink 2s steps(1) infinite;
}
.colon .csec{
  font-family:'Space Grotesk',sans-serif; font-weight:700; font-style:normal;
  font-size:0.16em; line-height:1; color:var(--text-dim);
  font-variant-numeric:tabular-nums;
}
.colon .cap{
  font-family:'Space Grotesk',sans-serif; font-weight:800; font-style:normal;
  font-size:0.15em; line-height:1; color:var(--accent-ink); opacity:0.9;
  letter-spacing:0.02em;
}
@keyframes blink{ 0%,49%{opacity:1;} 50%,100%{opacity:0.25;} }
/* Outline digits (Settings > Style > Digits): only the outline of each digit, in the clock's colour,
   no fill. The line is a fraction of the digit's size so it keeps its look from small to large, but
   never thinner than 2.5px, so a small clock's outline stays readable. The fill is made clear (not
   the text colour) so the colour still counts as the text colour for contrast. The clip margin
   (see below) grows with the line so the outer half of it isn't cut off. */
:root[data-digitfill="outline"] .time .hh, :root[data-digitfill="outline"] .time .mm{
  -webkit-text-fill-color:transparent;
  -webkit-text-stroke:max(0.03em, 2.5px) var(--accent);
  overflow-clip-margin:0.04em;
}
/* Stacked digits (Settings > Clock): hours above minutes, the colon turned on its side
   between them, seconds (and AM/PM) in it. measureTime measures this shape too. */
:root[data-clock="stack"] .time{ flex-direction:column; }
:root[data-clock="stack"] .colon, :root[data-clock="stack"] .colon.has-ampm{
  flex-direction:row; justify-content:center; gap:0.12em; width:auto; height:auto; margin:0.07em 0;
}
/* Seconds round the clock instead: the digits make way (keeping their space). */
:root[data-seconds="ring"] .colon .csec, :root[data-seconds="off"] .colon .csec{ visibility:hidden; }

/* ---------- race ring ----------
   A faint track around the digits, finish at 12 o'clock under a small triangle; running
   timers race round it (renderRing in app.js). The time's box grows by the ring's margins,
   so the ring is exactly that box. Racers are placed in % of it; their size is in em of the
   digits (.ti is 1.6em of a racer's 0.125em: a fifth of the digits' height). */
:root[data-ring] .time:not(.measure){
  padding:calc(var(--ring-y) * 1em) calc(var(--ring-x) * 1em);
  min-width:calc((var(--time-ratio) + 2 * var(--ring-x)) * 1em);
}
.ring{ display:none; position:absolute; inset:0; pointer-events:none; }
:root[data-ring] .time:not(.measure) .ring{ display:block; }
.ring .track{ position:absolute; inset:0; width:100%; height:100%; overflow:visible; }
.track-line{ fill:none; stroke:var(--text-dim); stroke-opacity:0.28; stroke-width:calc(1.5px * var(--ring-w, 1)); vector-effect:non-scaling-stroke; }
/* The line's other looks (Settings > Ring): lightning glows in the second accent; the wave
   glides from one shape to the next each second; widening and narrowing are filled shapes. */
.ring[data-line="lightning"] .track-line{ stroke:var(--accent2); stroke-opacity:0.6; stroke-linejoin:miter; filter:drop-shadow(0 0 2px var(--accent2)); }
.ring[data-line="wave"] .track-line{ stroke-opacity:0.4; transition:d 1s linear; }
.ring[data-line="widen"] .track-line, .ring[data-line="narrow"] .track-line{ fill:var(--text-dim); fill-opacity:0.3; stroke:none; }
.bezel{ fill:var(--text-dim); fill-opacity:0.75; }
.racer{
  position:absolute; font-size:calc(var(--racer-k, 0.125) * 1em); line-height:0;
  padding:0.12em; border-radius:50%;
  transform:translate(-50%, -50%);
  pointer-events:auto; cursor:pointer;
  transition:transform 0.28s cubic-bezier(0.3, 1.4, 0.5, 1), box-shadow 0.28s, background-color 0.28s;
}
.racer .ti{ display:block; }
.racer.far{ opacity:0.4; }
/* The next alarm on the ring: its icon in a thin ring of the alarm colour. */
.racer.alarm-racer{ box-shadow:inset 0 0 0 0.06em color-mix(in srgb, var(--accent) 70%, transparent); }
.racer.alarm-racer .ti-level{ color:var(--accent); }
.racer.paused .ti-level{ color:var(--text-dim); }
.racer.done .ti-level{ color:var(--accent); }
.racer.done .ti{ animation:pop 0.9s ease-in-out infinite; transform-origin:50% 70%; }
/* Point at a racer and it grows in place, keeping its level. */
.racer:hover{ transform:translate(-50%, -50%) scale(2.4); z-index:2; opacity:1; background:var(--bg-panel); box-shadow:0 0.15em 0.5em var(--shadow); }
.sec-hand{
  position:absolute; width:calc(0.05em * var(--ring-k, 1)); height:calc(0.05em * var(--ring-k, 1)); margin:calc(-0.025em * var(--ring-k, 1)) 0 0 calc(-0.025em * var(--ring-k, 1));
  border-radius:50%; background:var(--accent);
}

/* ---------- screen fill ----------
   Behind everything: a wash that empties (or fills) with the timer that ends next, with that
   timer's icon floating at the surface. Stronger on the dark theme, where a faint wash
   barely shows. Colour: one of six swatches (Settings > Timers); grey while paused and the
   alert colour when done. */
.fill{ position:fixed; inset:0; z-index:-1; pointer-events:none; --fill-c:var(--accent2); --fill-a:15%; --fill-edge:55%; }
:root[data-theme="light"] .fill{ --fill-a:10%; --fill-edge:40%; }
@media (prefers-color-scheme: light){ :root:not([data-theme="dark"]) .fill{ --fill-a:10%; --fill-edge:40%; } }
.fill.c-amber, .fill-tag.c-amber{ --fill-c:var(--accent); }
.fill.c-green, .fill-tag.c-green{ --fill-c:var(--fill-green); }
.fill.c-pink, .fill-tag.c-pink{ --fill-c:var(--fill-pink); }
.fill.c-purple, .fill-tag.c-purple{ --fill-c:var(--fill-purple); }
.fill.c-grey, .fill.paused, .fill-tag.c-grey, .fill-tag.paused{ --fill-c:var(--text-dim); }
.fill.done, .fill-tag.done{ --fill-c:var(--accent); }
.fill-level{
  position:absolute; left:0; bottom:0;
  background:color-mix(in srgb, var(--fill-c) var(--fill-a), transparent);
}
.fill.down .fill-level, .fill.up .fill-level{ right:0; border-top:2px solid color-mix(in srgb, var(--fill-c) var(--fill-edge), transparent); }
.fill.across .fill-level{ top:0; border-right:2px solid color-mix(in srgb, var(--fill-c) var(--fill-edge), transparent); }
/* (No transition: the level moves well under a pixel a second, and animating it would
   redraw the whole window every frame.) */
/* Bold: both colours stronger, for anyone who wants it plain to see. */
.fill.bold{ --fill-a:30%; --fill-edge:85%; }
:root[data-theme="light"] .fill.bold{ --fill-a:24%; --fill-edge:75%; }
@media (prefers-color-scheme: light){ :root:not([data-theme="dark"]) .fill.bold{ --fill-a:24%; --fill-edge:75%; } }
/* The rest of the screen, in a second colour. */
.fill.b-blue{ --fill-b:var(--accent2); }
.fill.b-amber{ --fill-b:var(--accent); }
.fill.b-green{ --fill-b:var(--fill-green); }
.fill.b-pink{ --fill-b:var(--fill-pink); }
.fill.b-purple{ --fill-b:var(--fill-purple); }
.fill.b-grey{ --fill-b:var(--text-dim); }
.fill:not(.b-none){ background:color-mix(in srgb, var(--fill-b) calc(var(--fill-a) * 0.8), transparent); }
/* Water: the level with two rows of waves on top, drifting both ways with Motion: Full. */
.fill.slosh .fill-level{ right:0; }
.fill.slosh .fill-level::before, .fill.slosh .fill-level::after{
  content:""; position:absolute; left:0; bottom:100%; width:200%; height:1.1rem; background:inherit;
  -webkit-mask:var(--wave) repeat-x 0 100% / 8rem 100%; mask:var(--wave) repeat-x 0 100% / 8rem 100%;
}
.fill.slosh .fill-level::after{ height:0.8rem; opacity:0.7; left:-4rem; }
.fill.slosh{ --wave:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 160 20' preserveAspectRatio='none'%3E%3Cpath d='M0 10C20 0 60 0 80 10S140 20 160 10V20H0z'/%3E%3C/svg%3E"); }
:root[data-motion="full"] .fill.slosh:not(.paused) .fill-level::before{ animation:slosh-a 7s linear infinite; }
:root[data-motion="full"] .fill.slosh:not(.paused) .fill-level::after{ animation:slosh-b 5s linear infinite; }
@keyframes slosh-a{ from{ transform:translateX(0); } to{ transform:translateX(-8rem); } }
@keyframes slosh-b{ 0%{ transform:translate(-8rem, 0); } 50%{ transform:translate(-4rem, 0.25rem); } 100%{ transform:translate(0, 0); } }
/* A circle that grows from the centre or shrinks to it (--r from app.js), with an edge. */
.fill.grow .fill-level, .fill.shrink .fill-level{
  inset:0; background:radial-gradient(circle at 50% 50%,
    color-mix(in srgb, var(--fill-c) var(--fill-a), transparent) calc(var(--r) - 2px),
    color-mix(in srgb, var(--fill-c) var(--fill-edge), transparent) calc(var(--r) - 2px) var(--r), transparent var(--r));
}
/* The timer's icon on the fill: over the page, so it can be pointed at (its name and time
   left show) and clicked (its card opens). */
.fill-tag{
  position:fixed; z-index:4; display:flex; align-items:center; gap:0.4rem; --fill-c:var(--accent2);
  padding:0.15rem; margin:0; border:none; border-radius:999px; background:none;
  color:var(--fill-c, var(--accent2)); font:inherit; cursor:pointer;
  transition:background-color 0.2s, box-shadow 0.2s;
}
.fill-tag .buoy{ width:1.3rem; height:1.3rem; flex-shrink:0; color:var(--fill-c); opacity:0.8; transition:transform 0.25s cubic-bezier(0.3, 1.4, 0.5, 1); }
.fill-tag .fill-name{ display:none; padding-right:0.5rem; font-size:0.85rem; font-weight:600; color:var(--text-dim); white-space:nowrap; }
.fill-tag.named .fill-name, .fill-tag:hover .fill-name, .fill-tag:focus-visible .fill-name{ display:inline; }
.fill-tag.named{ background:var(--bg-panel); box-shadow:0 0.2rem 0.6rem var(--shadow); }   /* (on a chip, so the name reads clearly over anything) */
.fill-tag:hover, .fill-tag:focus-visible{ background:var(--bg-panel); box-shadow:0 0.2rem 0.6rem var(--shadow); }
.fill-tag:hover .buoy, .fill-tag:focus-visible .buoy{ transform:scale(1.5); opacity:1; }
.fill-tag:hover .fill-name, .fill-tag:focus-visible .fill-name{ padding-left:0.3rem; color:var(--text); }

/* Quiet hours: the screen dims (the settings and pop-ups stay bright). */
:root[data-quiet] body::after{ content:""; position:fixed; inset:0; z-index:15; background:#000; opacity:0.45; pointer-events:none; }

/* ---------- weather band ----------
   Everything inside is sized in em of the band's font-size, which fitBand() sets so the
   whole band is as large as the leftover space allows. Icons are deliberately tall
   relative to the text: the band is usually width-bound, and taller icons use height
   that would otherwise go unused. */
.band{ font-size:16px; min-width:0; }
.now{ display:flex; flex-direction:column; align-items:center; gap:0.3em; }
.now svg{ width:5.2em; height:5.2em; color:var(--accent2); flex-shrink:0; }
.now .temp{ font-family:'Orbitron',sans-serif; font-weight:700; line-height:1; font-size:2.4em; color:var(--text); }
.info{ display:flex; flex-direction:column; align-items:flex-start; gap:0.4em; min-width:0; text-align:left; }
.date{ font-size:1.05em; font-weight:600; color:var(--text-dim); letter-spacing:0.02em; white-space:nowrap; }
.cond{ font-size:1.9em; font-weight:600; line-height:1.05; padding-bottom:0.14em; color:var(--text-dim); white-space:nowrap; }   /* (room for its descenders) */
.hilo-row{ display:flex; align-items:baseline; min-width:0; font-size:0.95em; color:var(--text-dim); white-space:nowrap; }
/* The place is a geocoded name with no length guarantee: truncate, never push. */
.hilo-row .place{ opacity:0.85; overflow:hidden; text-overflow:ellipsis; max-width:12em; }
.hilo-row .place::before{ content:" · "; opacity:0.6; white-space:pre; }
.forecast{ display:flex; align-items:center; gap:1.6em; }
.day{ display:flex; flex-direction:column; align-items:center; gap:0.35em; }
.day .d{ font-size:0.95em; font-weight:700; color:var(--text-dim); text-transform:uppercase; letter-spacing:0.05em; }
.day svg{ width:3.4em; height:3.4em; color:var(--accent2); }
.day .t{ font-size:1.1em; font-weight:700; font-variant-numeric:tabular-nums; color:var(--text); }
.day .t small{ color:var(--text-dim); }
/* A forecast day's chance of rain. */
.day .dx{ display:flex; flex-direction:column; align-self:center; gap:0.3em; font-size:0.8em; font-weight:600; color:var(--text-dim); }
.fx{ display:inline-flex; align-items:center; gap:0.25em; white-space:nowrap; font-variant-numeric:tabular-nums; }
.day .fx svg, :root[data-layout="stack"] .day .fx svg{ width:1.3em; height:1.3em; flex-shrink:0; color:var(--accent2); }
.day .fx .moon3d, :root[data-layout="stack"] .day .fx .moon3d{ width:1.5em; height:1.5em; color:var(--text-dim); }
.forecast.has-fx{ align-items:flex-start; }   /* (days with more extras are taller: keep their names in a line) */
.fxt{ display:flex; flex-direction:column; line-height:1.15; }
/* A forecast day's extras (Also show > Forecast): its chance of rain, moon and so on, small. */
/* Sun times: a half sun on the horizon. Tall and bright yellow at sunrise, a sliver and deep orange at
   sunset (the height tells them apart even where colours are overridden; the outline stays the text colour). */
.sun-r{ fill:#ffd23f; }
.sun-s{ fill:#ff6a13; }
@media (forced-colors: active){ .sun-r, .sun-s{ fill:CanvasText; } }
/* Today's extras (Settings > Weather > Also show): small icon-and-value pairs in a row. The
   next sunrise or sunset brightens through its last hour (--near from app.js, 0 to 1). */
.extras{ display:flex; align-items:center; gap:0.95em; font-size:0.95em; color:var(--text-dim); white-space:nowrap; }
.extras:empty{ display:none; }
.extras.rows{ display:grid; grid-template-columns:repeat(var(--cols), auto); justify-content:start; row-gap:0.45em; }
:root[data-layout="stack"] .extras.rows{ justify-content:center; }
.wx{ display:inline-flex; align-items:center; gap:0.3em; font-variant-numeric:tabular-nums; }
.wx svg{ width:1.35em; height:1.35em; flex-shrink:0; color:var(--accent2); }
.wx.sun svg{ color:var(--accent); }
.wx.sun.next{ color:color-mix(in srgb, var(--text) calc(var(--near, 0) * 100%), var(--text-dim)); }
.wx.sun.next svg{ filter:drop-shadow(0 0 calc(var(--near, 0) * 0.3em) var(--accent)); }
:root[data-motion="full"] .wx.sun.soon svg{ animation:sun-soon 2.4s ease-in-out infinite; }
@keyframes sun-soon{ 50%{ filter:drop-shadow(0 0 0.5em var(--accent)); } }
.wx .moon3d{ width:1.55em; height:1.55em; color:var(--text-dim); }
.wx.wear{ gap:0.2em; }
.wx.wear svg{ width:1.5em; height:1.5em; }
/* What to wear's size (Settings > Weather): the main item's icon at the chosen size, the others small beside it.
   Huge sits beside the weather icon, at its size (fitLayout steps down a size, to Big, when it doesn't fit). */
.band.wear-m .extras .wx.wear svg:not(.more){ width:2.8em; height:2.8em; }
.band.wear-l .extras .wx.wear svg:not(.more){ width:4.2em; height:4.2em; }
.now .wx.wear svg.more, .wx.wear svg.more{ width:1.5em; height:1.5em; }
.band.wear-xl .extras .wx.wear, .band:not(.wear-xl) .now .wx.wear{ display:none; }
.band.wear-xl .now.has-wear{ display:grid; grid-template-columns:auto auto; align-items:center; justify-items:center; column-gap:0.3em; }
.band.wear-xl .now .wx.wear svg:not(.more){ width:5.2em; height:5.2em; }   /* (as big as the weather icon) */
:root[data-layout="stack"] .band.wear-xl .now .wx.wear svg:not(.more){ width:4.4em; height:4.4em; }
.band.wear-xl .now.has-wear > svg{ grid-column:1; grid-row:1; }
.band.wear-xl .now.has-wear .wx.wear{ grid-column:2; grid-row:1; }
.band.wear-xl .now.has-wear .temp{ grid-column:1 / -1; grid-row:2; }
.band.wear-xl .extras.rows:not(.rows-x){ display:flex; }
.band.wear-xl .extras.rows{ grid-template-columns:repeat(var(--cols-x), auto); }
.band.date-only .extras, .band.no-data .extras{ display:none !important; }

/* Weather switched off (Settings > Show): the date only. */
.band.date-only .now, .band.date-only .cond, .band.date-only .hilo-row,
.band.date-only .forecast, .band.date-only .weather-status{ display:none !important; }
/* Just the date: no grid (its empty rows would still add gaps the layout fit doesn't count). */
.band.date-only, :root[data-layout="stack"] .band.date-only{ display:flex; justify-content:center; }
.band.date-only .date{ margin-bottom:0; }
/* Date switched off: the weather without it (and no empty grid row where it was). */
.band.no-date .date{ display:none !important; }
/* (Only rows that are shown: an empty row would still add a gap the layout fit can't see.) */
:root[data-layout="stack"] .band.no-date{ grid-template-areas:"now cond" "now hilo" "fc fc"; }
:root[data-layout="stack"] .band.no-data{ grid-template-areas:"date date" "status status"; }
:root[data-layout="stack"] .band.no-data.no-date{ grid-template-areas:"status status"; }
/* Unix time, for the geeks: a second line under the date. */
.date .dtext, .date .unix{ display:block; }
.date .unix{ position:relative; margin-top:0.25em; font-family:'Orbitron',sans-serif; font-size:0.85em; font-weight:700; letter-spacing:0.06em; font-variant-numeric:tabular-nums; opacity:0.75; cursor:help; }
:root[data-unix="s"] .date .unix{ font-size:0.7em; }
:root[data-unix="l"] .date .unix{ font-size:1.15em; }
/* Pointed at, Unix time breaks down into years, months, days... (data-tip from app.js). */
.date .unix:hover, .date .unix:focus-visible{ opacity:1; }
.date .unix:hover::after, .date .unix:focus-visible::after{
  content:attr(data-tip); position:absolute; left:var(--tip-x, 0px); bottom:calc(100% + 0.6rem); z-index:5;
  width:max-content; max-width:min(24rem, calc(100vw - 1rem)); padding:0.6rem 0.8rem; border-radius:0.6rem;
  background:var(--bg-panel); border:1px solid var(--divider); box-shadow:0 0.3rem 1rem var(--shadow);
  font-family:'Space Grotesk', system-ui, sans-serif; font-size:0.85rem; font-weight:500; letter-spacing:0; line-height:1.45;
  white-space:pre-line; color:var(--text); text-align:left;
}
.date .unix.tip-below::after{ bottom:auto; top:calc(100% + 0.6rem); }

/* Point at the weather and it comes alive (Motion: Full only): sun rays turn, clouds drift,
   rain and snow fall, the moon rocks, lightning flickers. Calm the rest of the time. */
.band .w-spin, .band .w-rock{ transform-box:fill-box; transform-origin:center; }
.band .w-spin-small{ transform-box:view-box; transform-origin:7px 7.5px; }
:root[data-motion="full"] .band:hover .w-spin, :root[data-motion="full"] .band:hover .w-spin-small{ animation:w-spin 8s linear infinite; }
:root[data-motion="full"] .band:hover .w-drift{ animation:w-drift 3s ease-in-out infinite; }
:root[data-motion="full"] .band:hover .w-fall{ animation:w-fall 1s linear infinite; }
:root[data-motion="full"] .band:hover .w-rock{ animation:w-rock 3s ease-in-out infinite; }
:root[data-motion="full"] .band:hover .w-flash{ animation:w-flash 2.2s steps(1) infinite; }
:root[data-motion="full"] .band:hover .w-d2{ animation-delay:-0.33s; }
:root[data-motion="full"] .band:hover .w-d3{ animation-delay:-0.66s; }
@keyframes w-spin{ to{ transform:rotate(360deg); } }
@keyframes w-drift{ 0%,100%{ transform:translateX(0); } 50%{ transform:translateX(1.2px); } }
@keyframes w-fall{ 0%{ transform:translateY(-2px); opacity:0; } 30%{ opacity:1; } 100%{ transform:translateY(2.5px); opacity:0; } }
@keyframes w-rock{ 0%,100%{ transform:rotate(-7deg); } 50%{ transform:rotate(7deg); } }
@keyframes w-flash{ 0%,100%{ opacity:1; } 8%{ opacity:0.2; } 12%{ opacity:1; } 16%{ opacity:0.3; } 20%{ opacity:1; } }

/* No weather yet (loading, no location, offline with no cache): only the date and a
   status line remain. */
.weather-status{ display:none; }
.band.no-data .now, .band.no-data .cond, .band.no-data .hilo-row, .band.no-data .forecast{ display:none; }
.band.no-data .weather-status{ display:flex; align-items:center; gap:0.6em; flex-wrap:wrap; max-width:18em; font-size:1.1em; color:var(--text-dim); }   /* (wraps, so it can be bigger) */
.weather-status button{
  background:none; border:1px solid var(--divider); color:var(--text-dim);
  border-radius:1em; padding:0.3em 0.9em; cursor:pointer;
}
.weather-status button:hover{ color:var(--text); border-color:var(--accent2); }

/* Split (wide windows): now | info | forecast in one row, edge to edge under the time;
   spare width goes evenly between the three groups. */
:root[data-layout="row"] .band{ display:flex; align-items:center; justify-content:space-between; gap:2.4em; }
:root[data-layout="row"] .band.no-data{ justify-content:center; }
/* While fitBand measures, pack the groups at their minimum gaps. */
.band.measuring{ width:max-content; justify-content:flex-start; }
.band.measuring > *{ flex-shrink:0; }

/* Stacked (portrait / squarer windows): .info dissolves (display:contents) so the date
   gets its own line and conditions + high/low pair up with the temperature. */
:root[data-layout="stack"] .band{
  display:grid;
  grid-template-columns:auto auto;
  grid-template-areas:"date date" "now cond" "now hilo" "fc fc";
  justify-content:center; justify-items:center;
  column-gap:1.6em; row-gap:0.7em;
}
:root[data-layout="stack"] .info{ display:contents; }
:root[data-layout="stack"] .date{ grid-area:date; font-size:1.3em; margin-bottom:0.4em; }
:root[data-layout="stack"] .now{ grid-area:now; }
:root[data-layout="stack"] .now svg{ width:4.4em; height:4.4em; }
:root[data-layout="stack"] .now .temp{ font-size:2.2em; }
:root[data-layout="stack"] .cond{ grid-area:cond; align-self:end; justify-self:start; font-size:2em; }
:root[data-layout="stack"] .hilo-row{ grid-area:hilo; align-self:start; justify-self:start; font-size:1.05em; }
:root[data-layout="stack"] .forecast{ grid-area:fc; gap:2em; margin-top:0.8em; }
:root[data-layout="stack"] .day svg{ width:3em; height:3em; }
:root[data-layout="stack"] .day .t{ font-size:1.15em; }
:root[data-layout="stack"] .weather-status{ grid-area:status; }

/* Sides (wide windows; Settings > Show > Layout): the time in the middle, today's weather (its
   icon and temperature, then the date and conditions) on one side, the forecast on the other,
   the timers underneath. The band dissolves, so its parts sit in the page's grid, still sized
   in em of the band; the spare width goes either side of the time. */
:root[data-layout="sides"] .primary{
  --tw:64cqw; --th:84cqh;
  grid-template-columns:auto auto minmax(0, 1fr) auto minmax(0, 1fr) auto;
  grid-template-areas:"now info . time . fc";
  column-gap:1.6cqw; align-items:center;
}
:root[data-layout="sides"][data-sides="right"] .primary{ grid-template-columns:auto minmax(0, 1fr) auto minmax(0, 1fr) auto auto; grid-template-areas:"fc . time . now info"; }
/* (While app.js measures the parts: each at its natural width, whatever room is left.) */
.primary.measuring-sides .now, .primary.measuring-sides .info, .primary.measuring-sides .forecast{ width:max-content; min-width:max-content; }
:root[data-layout="sides"] .band{ display:contents; }
:root[data-layout="sides"] .time{ grid-area:time; }
:root[data-layout="sides"] .now{ grid-area:now; }
:root[data-layout="sides"] .info{ grid-area:info; }
:root[data-layout="sides"] .forecast{ grid-area:fc; display:grid; grid-template-columns:repeat(2, auto); gap:1.2em 1.8em; }   /* (two by two: there's height to spare) */
:root[data-layout="sides"] .timers{ grid-column:1 / -1; }
/* Inside (the wide dial, with "Weather inside the dial" on): the same parts on the dial itself,
   either side of the hands' middle, each on a soft card so the hands pass under them;
   --inside-in (from app.js) keeps them clear of the dial's edge and numbers. */
:root[data-layout="inside"] .primary{
  --tw:97cqw; --th:78cqh;
  grid-template-columns:auto auto minmax(0, 1fr) auto; grid-template-areas:"now info . fc";
  column-gap:1.2cqw; align-items:center;
}
:root[data-layout="inside"][data-sides="right"] .primary{ grid-template-columns:auto minmax(0, 1fr) auto auto; grid-template-areas:"fc . now info"; }
:root[data-layout="inside"] .band{ display:contents; }
:root[data-layout="inside"] .time{ grid-column:1 / -1; grid-row:1; justify-self:center; }
:root[data-layout="inside"] .now{ grid-area:now; }
:root[data-layout="inside"] .info{ grid-area:info; }
:root[data-layout="inside"] .forecast{ grid-area:fc; }
:root[data-layout="inside"] .now, :root[data-layout="inside"] .info, :root[data-layout="inside"] .forecast{
  grid-row:1; z-index:1; padding:0.4em 0.6em; border-radius:0.7em; background:color-mix(in srgb, var(--bg-panel) 72%, transparent);
}
:root[data-layout="inside"][data-sides="left"] .now, :root[data-layout="inside"][data-sides="right"] .forecast{ margin-left:var(--inside-in, 0px); }
:root[data-layout="inside"][data-sides="left"] .forecast, :root[data-layout="inside"][data-sides="right"] .info{ margin-right:var(--inside-in, 0px); }
:root[data-layout="inside"] .timers{ grid-column:1 / -1; }
/* Tall (a dial not much wider than tall, data-inside from app.js): today's two cards one over
   the other at one end of the dial, the forecast as a list at the other. */
:root[data-layout="inside"][data-inside="tall"] .primary{
  grid-template-columns:auto minmax(0, 1fr) auto; grid-template-rows:1fr auto auto 1fr auto;
  grid-template-areas:". . ." "now . fc" "info . fc" ". . ." "pills pills pills"; row-gap:0;
}
:root[data-layout="inside"][data-inside="tall"][data-sides="right"] .primary{ grid-template-areas:". . ." "fc . now" "fc . info" ". . ." "pills pills pills"; }
:root[data-layout="inside"][data-inside="tall"] .time{ grid-row:1 / 5; }
:root[data-layout="inside"][data-inside="tall"] .now{ grid-area:now; align-self:end; justify-self:stretch; justify-content:center; }
:root[data-layout="inside"][data-inside="tall"] .info{ grid-area:info; align-self:start; margin-top:0.6em; }
:root[data-layout="inside"][data-inside="tall"] .forecast{ grid-area:fc; flex-direction:column; align-items:stretch; gap:0.5em; }
:root[data-layout="inside"][data-inside="tall"] .forecast .day{ flex-direction:row; justify-content:space-between; gap:0.7em; }
:root[data-layout="inside"][data-inside="tall"] .forecast .day .dx{ flex-direction:row; gap:0.6em; }
:root[data-layout="inside"][data-inside="tall"] .timers{ grid-area:pills; }
:root[data-layout="inside"][data-inside="tall"][data-sides="left"] .info, :root[data-layout="inside"][data-inside="tall"][data-sides="right"] .forecast{ margin-left:var(--inside-in, 0px); }
:root[data-layout="inside"][data-inside="tall"][data-sides="right"] .now{ margin-right:var(--inside-in, 0px); }
:root[data-layout="stack"] .extras{ grid-area:ex; }
/* Too little room for all of the band at a readable size (fitLayout in app.js): it shows less. */
.band.lean-1 .extras, .band.lean-1 .place, .band.lean-1 .now .wx.wear, .band.fx-off .dx, .band.lean-1 .dx{ display:none !important; }
.band.lean-1.wear-xl .now.has-wear{ display:flex; }
.band.lean-2 .hilo-row, .band.lean-2 .forecast .day:nth-child(n+3){ display:none; }
.band.lean-3 .forecast{ display:none; }
.band.lean-4 .cond{ display:none; }
.band.lean-5:not(.no-data) .info, .band.lean-5.date-only .info{ display:none; }   /* (the weather's message stays: it's all there is) */
.band.lean-6{ display:none !important; }   /* (over any layout's own display) */
:root[data-layout="stack"] .band.has-ex:not(.no-data):not(.date-only){ grid-template-areas:"date date" "now cond" "now hilo" "ex ex" "fc fc"; }
:root[data-layout="stack"] .band.has-ex.no-date:not(.no-data):not(.date-only){ grid-template-areas:"now cond" "now hilo" "ex ex" "fc fc"; }

/* ---------- running timers ----------
   The row only exists while a timer runs (hidden otherwise), so it costs no space.
   Everything is in em; fitLayout in app.js sets the font size so the pills fit with the
   time and weather, wrapping onto more lines when the window is narrow. */
.timers{
  display:flex; flex-wrap:wrap; justify-content:center; gap:0.6em;
  font-size:min(1.5rem, 1.8cqw);
}
/* While fitLayout measures: each pill at its natural width, on one line. */
.timers.measuring{ width:max-content; flex-wrap:nowrap; }
.timer{
  display:flex; align-items:center; gap:0.6em;
  padding:0.3em 0.35em 0.3em 0.45em;
  border:1px solid var(--divider); border-radius:999px;
  background:var(--bg-panel);
}
.timer .tl{ color:var(--text-dim); font-weight:600; white-space:nowrap; }
.timer .tr{
  font-family:'Orbitron',sans-serif; font-weight:700;
  color:var(--accent2); font-variant-numeric:tabular-nums;
}
/* The draining icon (drainEl in app.js): the outline, and a coloured copy in a box anchored
   to the bottom whose height is the time left, so the colour drains from the top. */
.ti{ position:relative; width:1.6em; height:1.6em; flex-shrink:0; }
.ti-base{ position:absolute; inset:0; color:var(--text-dim); opacity:0.5; }
.ti-level{ position:absolute; left:0; right:0; bottom:0; height:100%; overflow:hidden; color:var(--accent2); }
.ti-fill{ position:absolute; left:0; bottom:0; width:1.6em; height:1.6em; }
.ti-base, .ti-fill, .ci{ display:block; }
.ti svg, .ci svg{ display:block; width:100%; height:100%; }
.ti img, .ci img, .buoy img{ display:block; width:100%; height:100%; border-radius:50%; object-fit:cover; }
.ti-base.photo img{ filter:grayscale(1); }
.timer.paused .ti-level{ color:var(--text-dim); }
.timer.done .ti-level{ color:var(--accent); }
.timer.done .ti{ animation:pop 0.9s ease-in-out infinite; transform-origin:50% 70%; }
@keyframes pop{ 0%,100%{ transform:scale(1); } 40%{ transform:scale(1.2) rotate(-6deg); } 70%{ transform:scale(0.95) rotate(3deg); } }
/* The icon is a button: it opens the timer's card. Pointing at it grows it in place,
   keeping its level, on a disc so it reads over whatever is behind. */
.tico{
  position:relative; display:block; flex-shrink:0; padding:0; margin:0;
  background:none; border:none; border-radius:50%; cursor:pointer;
  transform-origin:50% 85%;
  transition:transform 0.28s cubic-bezier(0.3, 1.4, 0.5, 1), box-shadow 0.28s, background-color 0.28s;
}
.tico .ti{ display:block; }
.tico:hover, .tico:focus-visible{ transform:scale(3.2); z-index:3; background:var(--bg-panel); box-shadow:0 0.2em 0.6em var(--shadow); }
/* A small, coloured timer icon: quick-timer chips and the settings rows. */
.ci{ width:1.2em; height:1.2em; flex-shrink:0; color:var(--accent2); }
.tbtn{
  width:2em; height:2em; padding:0;
  display:flex; align-items:center; justify-content:center;
  background:none; border:none; border-radius:50%;
  color:var(--text-dim); cursor:pointer;
}
.tbtn:hover{ background:var(--divider); color:var(--text); }
.tbtn svg{ width:1.15em; height:1.15em; }   /* big enough to hit easily, still lighter than the time */
.tbtn.rep{ opacity:0.55; }
.tbtn.rep[aria-pressed="true"]{ opacity:1; color:var(--accent2); }
/* The next alarm, after the timers: a button that opens the alarm settings. */
.alarm-pill{ cursor:pointer; padding:0.3em 0.95em 0.3em 0.55em; }
.alarm-pill .ci{ width:1.4em; height:1.4em; color:var(--accent); }
.alarm-pill .tr{ color:var(--text); }
.alarm-pill:hover{ border-color:var(--accent2); }
/* Pointing at the alarm pill grows its icon or photo a little, as a timer's does. */
.alarm-pill .ci{ position:relative; border-radius:50%; transform-origin:90% 85%; transition:transform 0.28s cubic-bezier(0.3, 1.4, 0.5, 1), box-shadow 0.28s, background-color 0.28s; }
.alarm-pill:hover .ci, .alarm-pill:focus-visible .ci{ transform:scale(2); z-index:3; background:var(--bg-panel); box-shadow:0 0.2em 0.6em var(--shadow); }
.timer.paused .tr{ color:var(--text-dim); }
.timer.done{ border-color:var(--accent); animation:pulse 1.4s ease-in-out infinite; }
.timer.done .tl, .timer.done .tr{ color:var(--accent); }
@keyframes pulse{
  0%,100%{ box-shadow:0 0 0 0 transparent; }
  50%{ box-shadow:0 0 0 0.3em color-mix(in srgb, var(--accent) 25%, transparent); }
}

/* ---------- tools: alarms, quick timers, settings ----------
   Top-right corner; in the title-bar-less app they sit inside the title strip, just left
   of the window buttons. Each menu (alarm chips, quick-timer chips) appears while pointing
   at its icon (or after a click on it, for touch), so the clock stays clean the rest of the
   time. Menus float over the page (fitMenus in app.js places them), so opening one never
   pushes the other icons across the clock. */
.tools{
  position:fixed; z-index:20;
  top:env(titlebar-area-y, 0.4rem);
  right:calc(100vw - env(titlebar-area-x, 0px) - env(titlebar-area-width, 100vw) + 0.4rem);
  height:env(titlebar-area-height, 2rem);
  display:flex; align-items:center;
  app-region:no-drag; -webkit-app-region:no-drag;
}
.tool{
  width:2rem; height:2rem; padding:0;
  display:flex; align-items:center; justify-content:center;
  background:none; border:none; border-radius:50%;
  color:var(--text-dim);
  cursor:pointer; opacity:0.6; transition:opacity 0.15s;
}
:root[data-contrast="high"] .tool{ opacity:0.9; }
.tool:hover, .tool:focus-visible, .tools.open-timers #timer-btn, .tools.open-alarms #alarm-btn, .panel-open #gear{ opacity:0.9; }
.tool svg{ width:1.15rem; height:1.15rem; }
/* A menu: in a row ending at its icon's left edge, or, when that doesn't fit (narrow
   windows), in a column under the icon, scaled down if it's too tall. */
.quick{
  display:none; position:absolute; top:0; height:100%;
  align-items:center; gap:0.3rem; padding-right:0.3rem; transform-origin:top right;
}
.tools:has(#timer-btn:hover) #quick, #quick:hover, .tools.open-timers #quick, #quick:has(:focus-visible),
.tools:has(#alarm-btn:hover) #alarm-menu, #alarm-menu:hover, .tools.open-alarms #alarm-menu, #alarm-menu:has(:focus-visible){ display:flex; }
/* Under the icon, a gap of about a pointer's height: pointing at the icon opens the menu with
   its first chip (and its time) clear of the pointer, not under it. The gap is part of the menu,
   so the pointer can still cross it without the menu closing. */
.quick.col{ top:100%; height:auto; flex-direction:column; align-items:flex-end; padding:1.15rem 0 0; }
/* The quick timers are always a list dropping from the stopwatch, one timer per row, each starting
   with its time, so the pointer (which arrives from above and sits at the icon's right edge) only
   ever covers the end of a row. Too many rows for the window: the list scrolls (max-height from
   fitMenus), keeping the text a readable size. A 2px margin keeps the focus rings from being clipped. */
#quick.col{ align-items:stretch; gap:0.25rem; padding:1.15rem 2px 2px; margin-right:-2px; overflow-y:auto; overscroll-behavior:contain; }
#quick .chip{ justify-content:flex-start; border-radius:0.7rem; }
#quick .chip small{ min-width:3.2em; text-align:left; color:var(--text); font-weight:700; font-variant-numeric:tabular-nums; }
.tools.measuring .quick{ display:flex; visibility:hidden; }
.chip{
  display:inline-flex; align-items:center; gap:0.35em;
  background:var(--bg-panel); border:1px solid var(--divider); color:var(--text);
  border-radius:999px; padding:0.25rem 0.65rem 0.25rem 0.45rem;
  font-size:0.78rem; font-weight:600; white-space:nowrap; cursor:pointer;
}
.chip:hover{ border-color:var(--accent2); }
.chip small{ color:var(--text-dim); font-weight:500; font-size:1em; }
/* Alarm chips: time, name and a small on/off switch; a click turns the alarm on or off. */
.chip .at{ font-family:'Orbitron',sans-serif; font-weight:700; font-variant-numeric:tabular-nums; }
.chip .mini-sw{ position:relative; width:1.6em; height:0.95em; margin-left:0.2em; border-radius:1em; background:var(--divider); flex-shrink:0; }
.chip .mini-sw::after{ content:""; position:absolute; top:0.12em; left:0.12em; width:0.71em; height:0.71em; border-radius:50%; background:var(--text-dim); }
.chip[aria-pressed="true"] .mini-sw{ background:var(--accent); }
.chip[aria-pressed="true"] .mini-sw::after{ left:auto; right:0.12em; background:var(--bg); }
.chip[aria-pressed="false"] .ci, .chip[aria-pressed="false"] .at, .chip[aria-pressed="false"] bdi{ opacity:0.5; }
.chip.edit{ color:var(--text-dim); }

/* ---------- settings panel ----------
   Always fits the window, with nothing to scroll: fitPanel in app.js picks one column or
   two side by side (wide, short windows), then scales the panel down from its top-right
   corner only as much as the window needs. */
.panel{
  position:fixed; z-index:30;
  top:calc(env(titlebar-area-y, 0px) + env(titlebar-area-height, 2.4rem) + 0.3rem);
  right:calc(100vw - env(titlebar-area-x, 0px) - env(titlebar-area-width, 100vw) + 0.4rem);
  background:var(--bg-panel); border:1px solid var(--divider);
  border-radius:0.8rem; padding:0.9rem 1rem;
  display:none; flex-direction:column; gap:0.75rem;
  width:22rem;
  transform-origin:top right;
  box-shadow:0 0.5rem 1.5rem var(--shadow);
  text-align:left;
  font-size:0.85rem; color:var(--text-dim);
  app-region:no-drag; -webkit-app-region:no-drag;
}
.panel.open{ display:flex; }
/* Too little height to show it all at a readable size: it scrolls (fitPanel in app.js). */
.panel.scroll{ overflow-y:auto; overscroll-behavior:contain; scrollbar-width:thin; }
.panel.sticky-tabs .tabs{ position:sticky; top:-0.9rem; z-index:2; background:var(--bg-panel); padding-top:0.35rem; margin-top:-0.9rem; }
/* Tabs: an icon over a word each, the open one in the accent colour. */
/* Two rows of four (one row of eight with two columns of settings). */
.tabs{ display:grid; grid-template-columns:repeat(4, minmax(0, 1fr)); gap:0.15rem; margin:-0.35rem -0.45rem 0; padding-bottom:0.45rem; border-bottom:1px solid var(--divider); }
.panel.two-col .tabs{ grid-template-columns:repeat(8, minmax(0, 1fr)); }
.tabs button{
  min-width:0; display:flex; flex-direction:column; align-items:center; gap:0.2rem;
  padding:0.4rem 0.1rem 0.3rem; background:none; border:none; border-radius:0.55rem;
  color:var(--text-dim); font-size:0.66rem; font-weight:600; cursor:pointer;
}
.tabs button svg{ width:1.3rem; height:1.3rem; }
.tabs button:hover{ background:var(--divider); color:var(--text); }
.tabs button[aria-selected="true"]{ color:var(--accent-ink); background:color-mix(in srgb, var(--accent) 13%, transparent); }
.tab-body{ display:flex; flex-direction:column; gap:0.75rem; }
/* Two columns (wide, short windows): the open tab's rows flow down one column, then the next. */
.panel.open.two-col{ width:41rem; }
.panel.two-col .tab-body{ display:block; columns:2; column-gap:1.5rem; }
.panel.two-col .tab-body > *{ break-inside:avoid; margin-bottom:0.75rem; }
/* Settings > Style has two columns of its own (not the automatic flow above, which put one style's
   options in either column depending on how many rows there were): on the left the style grid and
   the options only the chosen style has; on the right those it shares with other styles, then
   the ones for every style. Narrow, they simply stack. */
.style-cols, .style-col{ display:flex; flex-direction:column; gap:0.75rem; }
.style-col{ min-width:0; }
.panel.two-col .tab-body[data-tab="style"]{ display:flex; flex-direction:column; columns:auto; }
.panel.two-col .style-cols{ flex-direction:row; align-items:flex-start; gap:1.5rem; }
.panel.two-col .style-col{ flex:1 1 0; }
.panel.two-col #style-right > .style-head.lead{ margin-top:0; padding-top:0; border-top:0; }
/* What to show: four big on/off tiles. */
.features{ display:grid; grid-template-columns:repeat(5, minmax(0, 1fr)); gap:0.3rem; }
.features button{
  position:relative; display:flex; flex-direction:column; align-items:center; gap:0.25rem;
  padding:0.55rem 0 0.45rem; min-width:0; background:var(--bg); border:1px solid var(--divider); border-radius:0.6rem;
  color:var(--text-dim); font-size:0.74rem; font-weight:600; cursor:pointer;
}
.features button svg{ width:1.55rem; height:1.55rem; }
.features button:hover{ border-color:var(--text-dim); }
.features button[aria-pressed="true"]{ border-color:var(--accent2); color:var(--text); background:color-mix(in srgb, var(--accent2) 14%, var(--bg)); }
.features button[aria-pressed="true"] svg{ color:var(--accent2); }
.features button[aria-pressed="false"]{ opacity:0.9; }   /* (off, yet its label still clearly readable) */
.features button[aria-pressed="true"]::after{
  content:""; position:absolute; top:0.3rem; right:0.3rem; width:0.45rem; height:0.45rem;
  border-radius:50%; background:var(--accent2);
}
.hint.warn{ color:var(--accent); opacity:1; }
/* An on/off switch. */
.switch{
  position:relative; flex-shrink:0; width:2.5rem; height:1.4rem; padding:0;
  border:none; border-radius:1rem; background:var(--divider); cursor:pointer;
  transition:background-color 0.15s;
}
.switch::after{
  content:""; position:absolute; top:0.17rem; left:0.17rem; width:1.06rem; height:1.06rem;
  border-radius:50%; background:var(--text-dim); transition:transform 0.15s, background-color 0.15s;
}
.switch[aria-checked="true"]{ background:var(--accent); }
.switch[aria-checked="true"]::after{ transform:translateX(1.1rem); background:var(--bg); }
/* A tab whose part is switched off says so, with a way to turn it on. */
.off-note{
  display:flex; align-items:center; justify-content:space-between; gap:0.5rem;
  padding:0.45rem 0.6rem; border-radius:0.5rem;
  background:color-mix(in srgb, var(--accent) 12%, transparent); color:var(--text); font-size:0.8rem;
}
.off-note button, .add-btn, .test-btn{
  background:var(--bg); border:1px solid var(--divider); color:var(--text); border-radius:0.45rem;
  padding:0.3rem 0.75rem; font-size:0.8rem; font-weight:600; cursor:pointer; white-space:nowrap;
}
.off-note button:hover, .add-btn:hover, .test-btn:hover{ border-color:var(--accent2); }
/* Rows that don't apply right now (fill off, sounds off): greyed and not clickable. */
.panel .disabled{ opacity:0.4; pointer-events:none; }
/* An option that can't do anything with the other choices as they are is left out (app.js
   applies()), and so is everything that needs a part turned off in Settings › Show. */
.panel .na, .a11y-card .na, .panel.no-clock [data-needs="clock"], .panel.no-date [data-needs="date"], .panel.no-weather [data-needs="weather"],
.panel.no-timers [data-needs="timers"], .panel.no-alarms [data-needs="alarms"]{ display:none !important; }
.big-label{ font-size:0.95rem; font-weight:600; color:var(--text); }
/* Colour swatches. */
.swatches{ display:flex; gap:0.35rem; }
.swatches button{
  width:1.4rem; height:1.4rem; padding:0; border:none; border-radius:50%; cursor:pointer;
  background:var(--sw); outline:2px solid transparent; outline-offset:2px;
}
.swatches button[aria-pressed="true"]{ outline-color:var(--text); }
.swatches [data-val="blue"]{ --sw:var(--accent2); }
.swatches [data-val="amber"]{ --sw:var(--accent); }
.swatches [data-val="green"]{ --sw:var(--fill-green); }
.swatches [data-val="pink"]{ --sw:var(--fill-pink); }
.swatches [data-val="purple"]{ --sw:var(--fill-purple); }
/* "None": an empty circle, struck through. */
.swatches [data-val="none"]{ background:linear-gradient(135deg, transparent 45%, var(--text-dim) 45% 55%, transparent 55%); box-shadow:inset 0 0 0 1.5px var(--text-dim); }
.swatches [data-val="grey"]{ --sw:var(--text-dim); }
/* Sounds off: a crossed-out speaker by the corner icons, always visible, one click to undo. */
.tool.muted-tool{ opacity:0.85; color:var(--accent); }
/* A plain-language note about a system setting that overrides the app's (motion). */
.notice{
  display:flex; flex-direction:column; align-items:flex-start; gap:0.4rem;
  padding:0.5rem 0.6rem; border-radius:0.5rem; font-size:0.78rem; line-height:1.35;
  background:color-mix(in srgb, var(--accent) 12%, transparent); color:var(--text);
}
.notice a{
  padding:0.3rem 0.7rem; border:1px solid var(--divider); border-radius:0.45rem;
  background:var(--bg); color:var(--text); font-weight:600; text-decoration:none;
}
.notice a:hover{ border-color:var(--accent2); }
.add-btn{ padding:0.5rem; border-style:dashed; }
/* Alarms: icon, time, name; the days it rings; on/off and delete. */
.alarms{ display:flex; flex-direction:column; gap:0.4rem; }
.alarms:empty{ display:none; }
.alarm{
  display:grid; grid-template-columns:2.1rem 7.8rem minmax(0, 1fr); gap:0.35rem; align-items:center;
  padding:0.4rem; border:1px solid var(--divider); border-radius:0.6rem; font-size:0.78rem;
}
.alarm.off > :not(.alarm-foot){ opacity:0.5; }
.alarm-foot{ grid-column:1 / -1; display:flex; align-items:center; gap:0.45rem; }
.alarm-foot .sum{ flex:1; min-width:0; font-size:0.72rem; color:var(--text-dim); }
.alarm-foot .sum.warn{ color:var(--accent); }
.date-formats{ display:grid; grid-template-columns:1fr 1fr; gap:0.3rem; }
.date-formats button{
  padding:0.4rem 0.3rem; border:1px solid var(--divider); border-radius:0.45rem; background:var(--bg);
  color:var(--text-dim); font-size:0.8rem; cursor:pointer; white-space:nowrap;
}
.date-formats button:hover{ border-color:var(--text-dim); }
.date-formats button[aria-pressed="true"]{ border-color:var(--accent); color:var(--text); background:color-mix(in srgb, var(--accent) 14%, var(--bg)); }
.date-formats button:last-child:nth-child(odd){ grid-column:1 / -1; }
.alarm-days{ grid-column:1 / -1; display:grid; grid-template-columns:repeat(7, minmax(0, 1fr)); gap:0.2rem; }
.alarm-days button{
  padding:0.32rem 0; border:1px solid var(--divider); border-radius:0.4rem; background:none;
  color:var(--text-dim); font-size:0.72rem; font-weight:600; cursor:pointer;
}
.alarm-days button.weekend{ border-style:dashed; }
.alarm-days button:hover{ border-color:var(--text-dim); }
.alarm-days button[aria-pressed="true"]{ background:var(--accent); border-color:var(--accent); border-style:solid; color:var(--bg); }
.panel .alarm input[type="time"]{ font-size:0.95rem; font-weight:700; padding:0.3rem 0.4rem; }
.alarm .tbtn.del{ font-size:1rem; }
.tbtn.del svg{ width:1.1em; height:1.1em; }
#volume{ flex:1; min-width:0; accent-color:var(--accent); }
.quiet-times{ display:flex; align-items:center; gap:0.4rem; font-size:0.8rem; }
.quiet-times input{ flex:1; }
.panel-row{ display:flex; align-items:center; justify-content:space-between; gap:0.6rem; }
.panel-col{ display:flex; flex-direction:column; align-items:stretch; gap:0.35rem; }
.dim{ opacity:0.85; }
/* Never squeezed: with overflow:hidden a shrunk group clips its last button; the label
   beside it wraps instead. */
.seg{ display:flex; flex-shrink:0; border:1px solid var(--divider); border-radius:0.5rem; overflow:hidden; }
.seg button{
  background:none; border:none; color:var(--text-dim);
  font-size:0.78rem; padding:0.3rem 0.6rem; cursor:pointer;
}
.seg button.active{ background:var(--accent-ink); color:var(--bg); font-weight:700; }
.seg button:focus-visible{ outline:2px solid var(--accent2); outline-offset:-3px; }
.seg.wide{ align-self:stretch; }
.seg.wide button{ flex:1; }
.panel input[type="text"], .panel input[type="number"], .panel input[type="time"]{
  width:100%; min-width:0;
  background:var(--bg); border:1px solid var(--divider); color:var(--text);
  border-radius:0.4rem; padding:0.4rem 0.5rem; font-family:inherit; font-size:0.82rem;
}
.loc-list{ display:flex; flex-direction:column; gap:0.2rem; }
/* Names typed or found in Hebrew, Arabic... align to their own start (dir="auto" in app.js). */
.panel input[type="text"], .loc-list button{ text-align:start; }
.loc-list button{
  text-align:left; background:none; border:none; color:var(--text); overflow-wrap:anywhere;
  font-size:0.78rem; padding:0.25rem 0.2rem; cursor:pointer; border-radius:0.3rem;
}
.loc-list button:hover{ background:var(--divider); }
.presets{ display:flex; flex-direction:column; gap:0.3rem; }
.preset{ display:grid; grid-template-columns:2.1rem 1fr 4.2rem auto auto; gap:0.35rem; align-items:center; font-size:0.78rem; }
.preset .tbtn.del{ font-size:1rem; width:1.6rem; }
.preset .tbtn.del[hidden]{ display:block !important; visibility:hidden; }   /* keeps the column, so rows line up */
.picon{
  height:100%; min-height:2rem; padding:0;
  display:flex; align-items:center; justify-content:center;
  background:var(--bg); border:1px solid var(--divider); border-radius:0.4rem; cursor:pointer;
}
.picon[aria-expanded="true"]{ border-color:var(--accent2); }
.picon .ci{ width:1.3rem; height:1.3rem; }
/* The icon picker, opened under a preset row. */
.picker{
  display:grid; grid-template-columns:repeat(6, minmax(0, 1fr)); gap:0.3rem;
  padding:0.4rem; border:1px solid var(--divider); border-radius:0.5rem; background:var(--bg);
}
.picker button{
  height:2.1rem; padding:0;
  display:flex; align-items:center; justify-content:center;
  background:none; border:1px solid transparent; border-radius:0.4rem;
  color:var(--text-dim); cursor:pointer;
}
.picker button:hover{ border-color:var(--divider); color:var(--text); }
.picker button.on{ border-color:var(--accent2); color:var(--accent2); background:color-mix(in srgb, var(--accent2) 14%, transparent); }
.picker button svg{ width:1.3rem; height:1.3rem; }
.picker .photo-btn{ grid-column:1 / -1; gap:0.4rem; font:inherit; font-size:0.78rem; font-weight:600; }
.picker .hint{ grid-column:1 / -1; }
.hint{ font-size:0.7rem; color:var(--text-dim); }
.panel-foot{
  display:flex; flex-wrap:wrap; justify-content:space-between; gap:0.4rem 0.6rem;
  padding-top:0.6rem; border-top:1px solid var(--divider);
  font-size:0.7rem;
}
.panel-foot a{ color:var(--text-dim); }
.panel-foot a:hover{ color:var(--text); }
.foot-links{ display:flex; gap:0.9rem; margin-left:auto; }
/* Who makes it: the app's icon and name, linking to the maker's site. */
.panel-foot .brand{ display:inline-flex; align-items:center; gap:0.35rem; color:var(--text); font-weight:600; text-decoration:none; }
.panel-foot .brand img{ width:1.35rem; height:1.35rem; border-radius:0.3rem; }
.panel-foot .brand .by{ color:var(--text-dim); font-weight:500; }
.panel-foot .brand:hover .by{ color:var(--text); text-decoration:underline; }
.foot-links svg{ width:1.15em; height:1.15em; vertical-align:-0.25em; margin-right:0.3em; }

/* ---------- pop-up cards ----------
   Over the clock: a timer's finish or an alarm (#finish: the icon large, with its own short
   animation, its name and two buttons), a timer's card (#tcard), the keyboard shortcuts
   (#keys) and the first-start welcome (#welcome). Everything is in em of the card, which
   fitSheets in app.js sizes to the window. Each animated part's resting state is its last
   frame, so with motion off the picture is still complete. */
.sheet{
  position:fixed; inset:0; z-index:25;
  display:flex; align-items:center; justify-content:center;
  background:color-mix(in srgb, var(--bg) 96%, transparent);   /* (nearly solid: nothing behind competes with its text) */
  animation:finish-in 0.3s ease-out both;
}
#welcome.sheet, #looks.sheet{ background:var(--bg); }
.keys-list.off dt, .keys-list.off dd{ opacity:0.45; }
.sheet-card{
  display:flex; flex-direction:column; align-items:center; gap:0.9em; flex-shrink:0;
  font-size:16px; text-align:center;
}
.sheet-art{ width:15em; height:15em; display:flex; align-items:center; justify-content:center; color:var(--accent2); }
.sheet-art svg{ width:100%; height:100%; overflow:visible; }
.sheet-title{ max-width:12em; font-size:2.3em; font-weight:700; line-height:1.1; color:var(--accent); }
.sheet-sub{ max-width:24em; font-size:1.15em; font-weight:500; line-height:1.35; color:var(--text-dim); }
.sheet-note{ font-size:0.9em; color:var(--text-dim); }
.sheet-actions{ display:flex; gap:0.75em; margin-top:0.3em; }
.sheet-actions button, .tcard-actions button{
  min-height:2.75em; padding:0 1.4em;
  border:1px solid var(--divider); border-radius:999px; background:var(--bg-panel);
  color:var(--text-dim); font:inherit; font-size:1.1em; font-weight:600; cursor:pointer; white-space:nowrap;
  display:inline-flex; align-items:center; justify-content:center; gap:0.45em; line-height:1; text-align:center;   /* (labels sit centred, whatever the font's metrics) */
}
.sheet-actions button:hover, .tcard-actions button:hover{ color:var(--text); border-color:var(--text-dim); }
.sheet-actions .primary{ border-color:var(--accent); color:var(--accent-ink); }
.sheet-actions .sheet-pin svg{ width:1.1em; height:1.1em; flex:none; }
.sheet-actions .sheet-pin[aria-pressed="true"]{ border-color:var(--accent2); color:var(--accent2); background:color-mix(in srgb, var(--accent2) 14%, var(--bg-panel)); }
.sheet-actions .sheet-pin[aria-pressed="true"] svg{ fill:currentColor; fill-opacity:0.35; }
.keys-note a, #keys-off a{ color:var(--accent2-ink); text-decoration:underline; text-underline-offset:0.15em; cursor:pointer; }
.keys-note a:hover, #keys-off a:hover{ color:var(--text); }
.keys-note a:focus-visible, #keys-off a:focus-visible{ outline:2px solid var(--accent2); outline-offset:2px; border-radius:2px; }
#finish .sheet-actions .primary{ animation:pulse 1.4s ease-in-out infinite; }
/* A timer's card: the icon big and draining, the time left, four large labelled buttons. */
.tcard-art{
  display:flex; align-items:center; justify-content:center; width:9em; height:9em;
  border-radius:50%; background:var(--bg-panel); border:1px solid var(--divider);
}
.tcard-art .ti, .tcard-art .ti-fill{ width:5.2em; height:5.2em; }
.tcard-art.paused .ti-level{ color:var(--text-dim); }
.tcard-art.done .ti-level{ color:var(--accent); }
#tcard-sub{ font-family:'Orbitron',sans-serif; font-weight:700; font-variant-numeric:tabular-nums; color:var(--accent2); }
.tcard-actions{ display:grid; grid-template-columns:1fr 1fr; gap:0.6em; margin-top:0.3em; }
.tcard-actions button{ display:flex; align-items:center; justify-content:center; gap:0.5em; color:var(--text); }
.tcard-actions button svg{ width:1.1em; height:1.1em; flex-shrink:0; }
.tcard-actions button[aria-pressed="true"]{ border-color:var(--accent2); color:var(--accent2); background:color-mix(in srgb, var(--accent2) 14%, var(--bg-panel)); }
.sheet-close{
  background:none; border:none; padding:0.3em 0.8em; cursor:pointer;
  color:var(--text-dim); font:inherit; font-size:1em; text-decoration:underline;
}
/* Keyboard shortcuts. */
.keys-list{ display:grid; grid-template-columns:auto auto; gap:0.6em 1.2em; align-items:center; margin:0.2em 0 0; font-size:1.05em; text-align:left; }
.keys-list dt{ justify-self:end; white-space:nowrap; color:var(--text-dim); }
.keys-list dd{ margin:0; white-space:nowrap; color:var(--text); }
kbd{
  display:inline-block; min-width:1.7em; padding:0.15em 0.45em;
  border:1px solid var(--divider); border-bottom-width:2px; border-radius:0.35em;
  background:var(--bg-panel); color:var(--text); font:inherit; font-weight:700; text-align:center;
}
/* First start: while the welcome card shows, the corner icons stay bright above it, each
   pointed out by a label (placed by placePointers in app.js). */
body.welcome-open .tools{ z-index:26; }
body.welcome-open .tool:not([hidden]){
  opacity:1; color:var(--accent2);
  background:color-mix(in srgb, var(--accent2) 18%, var(--bg));
  box-shadow:0 0 0 2px color-mix(in srgb, var(--accent2) 50%, transparent);
}
:root[data-motion="full"] body.welcome-open .tool:not([hidden]){ animation:glow 1.6s ease-in-out 3; }
@keyframes glow{ 50%{ box-shadow:0 0 0 0.45rem color-mix(in srgb, var(--accent2) 25%, transparent); } }
/* The line in the card that points the way, and the dotted curve from it to the corner. */
.welcome-corner{ color:var(--accent2-ink); font-size:1.05em; font-weight:600; }
.pointer-curve{ position:absolute; inset:0; width:100%; height:100%; overflow:visible; }
.pointer-curve path{ fill:none; stroke:var(--accent2); stroke-width:2; stroke-dasharray:2 7; stroke-linecap:round; opacity:0.85; }
.pointer-curve .head{ stroke-dasharray:none; stroke-width:2.5; }
.pointers{ position:fixed; inset:0; pointer-events:none; }
.pointer{
  position:absolute; display:flex; flex-direction:column; align-items:flex-end;
  color:var(--accent2); font-size:0.95rem; font-weight:600; white-space:nowrap;
}
.pointer i{ display:block; width:2px; margin-right:9px; background:color-mix(in srgb, var(--accent2) 60%, transparent); border-radius:1px; }
.pointer i::before{
  content:""; display:block; width:8px; height:8px; margin:-1px 0 0 -3px;
  border-left:2px solid var(--accent2); border-top:2px solid var(--accent2); transform:rotate(45deg);
}
/* First start. */
.welcome-art{ display:flex; gap:1em; color:var(--accent2); }
.welcome-art svg{ width:3em; height:3em; }
.welcome-art svg:first-child{ color:var(--accent); }
.finish-photo{ width:7.5em; height:7.5em; margin:3.75em; border-radius:50%; overflow:hidden; box-shadow:0 0 0 0.3em var(--accent2); }
/* Your photos square (Settings > Timers or Alarms): rounded corners instead of a circle. */
:root[data-photo="square"] .finish-photo, :root[data-photo="square"] .ti img, :root[data-photo="square"] .ci img, :root[data-photo="square"] .buoy img{ border-radius:18%; }
/* Pills with just the icon, or just the name (the name then opens the card). */
:root[data-pill="icon"] .timer:not(.alarm-pill) .tl{ display:none; }
:root[data-pill="name"] .timer:not(.alarm-pill) .tico, :root[data-pill="name"] .alarm-pill .ci{ display:none; }
.timer .tl{ cursor:pointer; }
.finish-photo img{ display:block; width:100%; height:100%; object-fit:cover; }
.fx-accent{ stroke:var(--accent); }
.fx-disc{ fill:var(--bg); stroke:none; }   /* keeps the dimmed clock from showing through light icons */
.fx-burst, .fx-ripple, .fx-wave{ stroke-width:3; }
.fx-burst{ opacity:0.25; transform-box:fill-box; transform-origin:center; animation:fx-burst 1.8s ease-out infinite; }
.fx-ripple{ opacity:0.5; transform-box:fill-box; transform-origin:center; animation:fx-ripple 1.8s ease-out infinite both; }
.fx-fall{ transform-box:fill-box; transform-origin:50% 100%; animation:fx-fall 1.8s cubic-bezier(0.45, 0, 0.7, 0.55) infinite; }
.fx-jump{ transform-box:fill-box; transform-origin:50% 100%; animation:fx-jump 1.1s ease-in-out infinite; }
.fx-shadow{ opacity:0.3; transform-box:fill-box; transform-origin:center; animation:fx-shadow 1.1s ease-in-out infinite; }
.fx-hit{ transform-box:fill-box; transform-origin:center; animation:fx-hit 1.9s ease-out infinite; }
.fx-arrow{ animation:fx-arrow 1.9s cubic-bezier(0.2, 0.7, 0.3, 1) infinite both; }
.fx-steam{ opacity:0.8; animation:fx-steam 2.1s ease-in-out infinite both; }
.fx-swing{ transform-box:fill-box; transform-origin:50% 8%; animation:fx-swing 1s ease-in-out infinite; }
.fx-buzz{ animation:fx-buzz 0.9s linear infinite; }
.fx-wave{ opacity:0.6; animation:fx-wave 1.2s ease-out infinite both; }
.fx-rock{ transform-box:fill-box; transform-origin:50% 60%; animation:fx-rock 2.4s ease-in-out infinite; }
.fx-twinkle{ animation:fx-twinkle 1.6s ease-in-out infinite both; }
.fx-grow{ transform-box:fill-box; transform-origin:50% 100%; animation:fx-grow 1.6s ease-out infinite; }
.fx-lift{ transform-box:fill-box; transform-origin:50% 100%; animation:fx-lift 1.2s ease-in-out infinite; }
.fx-bounce{ transform-box:fill-box; transform-origin:50% 100%; animation:fx-bounce 1s ease-in-out infinite; }
.fx-reveal{ animation:fx-reveal 2.4s cubic-bezier(0.3, 0.7, 0.3, 1) both; }
/* After the animations above, so the delay isn't reset by their shorthand. */
.fx-late{ animation-delay:0.3s; }
.fx-later{ animation-delay:0.6s; }
@keyframes finish-in{ from{ opacity:0; } to{ opacity:1; } }
@keyframes fx-burst{ 0%{ opacity:0.5; transform:scale(0.7); } 100%{ opacity:0; transform:scale(1.15); } }
@keyframes fx-ripple{ 0%,40%{ opacity:0; transform:scale(0.25); } 46%{ opacity:0.9; transform:scale(0.3); } 100%{ opacity:0; transform:scale(1.5); } }
@keyframes fx-fall{ 0%{ transform:translateY(-55%); } 42%{ transform:translateY(0) scale(1); } 52%{ transform:scale(1.18, 0.8); } 66%{ transform:scale(0.94, 1.06); } 78%,100%{ transform:scale(1); } }
@keyframes fx-jump{ 0%,100%{ transform:translateY(0) scale(1); } 12%{ transform:scale(1.06, 0.92); } 40%{ transform:translateY(-22%) rotate(-5deg); } 62%{ transform:translateY(0) rotate(0); } 74%{ transform:scale(1.05, 0.94); } }
@keyframes fx-shadow{ 0%,100%{ transform:scale(1); opacity:0.3; } 40%{ transform:scale(0.6); opacity:0.12; } }
@keyframes fx-hit{ 0%,30%,60%,100%{ transform:scale(1); } 36%{ transform:scale(0.92); } 46%{ transform:scale(1.05); } }
@keyframes fx-arrow{ 0%{ transform:translateX(-80px); opacity:0; } 8%{ opacity:1; } 32%{ transform:translateX(0); } 38%{ transform:rotate(-3deg); } 44%{ transform:rotate(2deg); } 50%,100%{ transform:none; } }
@keyframes fx-steam{ 0%{ opacity:0; transform:translateY(16px); } 35%{ opacity:0.9; } 100%{ opacity:0; transform:translateY(-30px); } }
@keyframes fx-swing{ 0%,100%{ transform:rotate(0); } 20%{ transform:rotate(14deg); } 45%{ transform:rotate(-12deg); } 70%{ transform:rotate(6deg); } }
@keyframes fx-buzz{ 0%,40%,100%{ transform:translate(0, 0); } 5%,15%,25%,35%{ transform:translate(-3px, 0) rotate(-2deg); } 10%,20%,30%{ transform:translate(3px, 0) rotate(2deg); } }
@keyframes fx-wave{ 0%{ opacity:0; } 30%{ opacity:0.8; } 100%{ opacity:0; } }
@keyframes fx-rock{ 0%,100%{ transform:rotate(-8deg); } 50%{ transform:rotate(8deg); } }
@keyframes fx-twinkle{ 0%,100%{ opacity:0.2; } 50%{ opacity:1; } }
@keyframes fx-grow{ 0%{ transform:scale(0.7, 0.5); } 55%{ transform:scale(1.04, 1.08); } 75%,100%{ transform:scale(1); } }
@keyframes fx-lift{ 0%,100%{ transform:translateY(0); } 45%,55%{ transform:translateY(-18%); } }
@keyframes fx-bounce{ 0%,100%{ transform:translateY(0) scale(1); } 15%{ transform:scale(1.08, 0.9); } 45%{ transform:translateY(-16%) scale(0.97, 1.04); } 70%{ transform:translateY(0) scale(1.04, 0.96); } }
@keyframes fx-reveal{ from{ clip-path:circle(0% at 50% 55%); } to{ clip-path:circle(75% at 50% 50%); } }

/* ---------- motion ----------
   data-motion (app.js): "full"; "calm", where nothing moves by itself (no blinking, pulsing
   or looping; a finish plays once; things still respond to the pointer); or "off", where
   nothing moves at all. Off whenever Windows has animation effects off. */
:root[data-motion="full"] .app{ transition:transform 2s ease-in-out; }   /* the screen-protection shift */
:root[data-motion="calm"] .colon .dot,
:root[data-motion="calm"] .timer.done, :root[data-motion="calm"] .timer.done .ti,
:root[data-motion="calm"] .racer.done .ti,
:root[data-motion="calm"] #finish .sheet-actions .primary{ animation:none; }
:root[data-motion="calm"] .sheet-art *{ animation-iteration-count:1 !important; }
:root[data-motion="off"] *, :root[data-motion="off"] *::before, :root[data-motion="off"] *::after{
  animation:none !important; transition:none !important;
}

/* ---------- clock faces (Settings > Style) ----------
   The digits are styled above. Any other face draws inside .face, sized in em of the time's
   font (app.js sets its width and height from the face's size); --ch on a part is that part's
   height in em, so text inside it scales with it. Colours come from the theme tokens, plus
   these: flip cards, and the tear-off paper (which follows the theme unless one is picked). */
:root{
  --card-a:#1b2029; --card-b:#151921;
  --paper:#1e232c; --paper-ink:#eceef2; --paper-red:#ff8a7a; --paper-edge1:#2c323d; --paper-edge2:#242933;
}
@media (prefers-color-scheme: light){
  :root{ --card-a:#ffffff; --card-b:#efece5; --paper:#fbf7ee; --paper-ink:#1b1f27; --paper-red:#c8463d; --paper-edge1:#ddd6c6; --paper-edge2:#c9c1ae; }
}
:root[data-theme="dark"]{ --card-a:#1b2029; --card-b:#151921; --paper:#1e232c; --paper-ink:#eceef2; --paper-red:#ff8a7a; --paper-edge1:#2c323d; --paper-edge2:#242933; }
:root[data-theme="light"]{ --card-a:#ffffff; --card-b:#efece5; --paper:#fbf7ee; --paper-ink:#1b1f27; --paper-red:#c8463d; --paper-edge1:#ddd6c6; --paper-edge2:#c9c1ae; }
:root[data-paper="cream"]{ --paper:#f3eee3; --paper-ink:#1b1f27; --paper-red:#c8463d; --paper-edge1:#d8d1c1; --paper-edge2:#bdb6a6; }
:root[data-paper="white"]{ --paper:#ffffff; --paper-ink:#14181f; --paper-red:#cc3b3b; --paper-edge1:#e1e1e1; --paper-edge2:#c6c6c6; }
:root[data-paper="night"]{ --paper:#1e232c; --paper-ink:#eceef2; --paper-red:#ff8a7a; --paper-edge1:#2c323d; --paper-edge2:#242933; }

/* High contrast (Settings > Style): the dim greys get much closer to the text colour. */
:root[data-contrast="high"]{ --text-dim:#cdd4de; --divider:rgba(255,255,255,0.22); }
@media (prefers-color-scheme: light){
  :root[data-contrast="high"]:not([data-theme="dark"]){ --text-dim:#2b313b; --divider:rgba(0,0,0,0.28); --accent:#8f5200; --accent2:#085a7a; }
}
:root[data-contrast="high"][data-theme="dark"]{ --text-dim:#cdd4de; --divider:rgba(255,255,255,0.22); }
:root[data-contrast="high"][data-theme="light"]{ --text-dim:#2b313b; --divider:rgba(0,0,0,0.28); --accent:#8f5200; --accent2:#085a7a; }

/* The colon's dots can stay still; with the seconds off they go too. */
:root[data-blink="off"] .colon .dot{ animation:none; }

/* Big and small digits: one part shrinks, sitting on the same line as the big one; "Minutes,
   huge" keeps the hour small, up in the corner. */
:root[data-face="digits"][data-emph="hour"] .time .mm,
:root[data-face="digits"][data-emph="minutes"] .time .hh{ font-size:0.5em; }
:root[data-face="digits"][data-emph="hour"] .time .colon,
:root[data-face="digits"][data-emph="minutes"] .time .colon{ font-size:0.62em; }
:root[data-face="digits"][data-emph="minonly"] .time .hh{ font-size:0.32em; align-self:flex-start; }
:root[data-face="digits"][data-emph="minonly"] .time .colon{ font-size:0.45em; }
:root[data-numfont="clean"] .colon .csec{ letter-spacing:0; }
:root[data-face="digits"][data-emph="hour"]:not([data-clock="stack"]) .time,
:root[data-face="digits"][data-emph="minutes"]:not([data-clock="stack"]) .time{ align-items:flex-end; }
:root[data-numfont="clean"] .time{ font-family:'Space Grotesk',sans-serif; font-weight:700; letter-spacing:-0.02em; }

.face{
  display:none; position:relative; flex-shrink:0; overflow:hidden;
  font-family:'Space Grotesk',sans-serif; font-weight:700; letter-spacing:0; line-height:1;
  color:var(--accent); white-space:nowrap;
}
:root[data-face]:not([data-face="digits"]) .time .face{ display:block; }
:root[data-face]:not([data-face="digits"]) .time > .hh,
:root[data-face]:not([data-face="digits"]) .time > .colon,
:root[data-face]:not([data-face="digits"]) .time > .mm{ display:none; }
.sr-only{ position:absolute; width:1px; height:1px; overflow:hidden; clip-path:inset(50%); white-space:nowrap; }
/* Square-ish faces get a little more of the window's height. */
:root[data-face="analog"][data-layout="row"] .primary, :root[data-face="grid"][data-layout="row"] .primary{ --th:60cqh; }
:root[data-face="analog"][data-layout="stack"] .primary, :root[data-face="grid"][data-layout="stack"] .primary{ --th:42cqh; }

/* Flip cards: two halves, each a window onto the whole number, and two flaps that fold. */
.fc{ position:absolute; border-radius:calc(var(--ch) * 0.08em); overflow:hidden; box-shadow:0 calc(var(--ch) * 0.03em) calc(var(--ch) * 0.1em) var(--shadow); }
.fh{ position:absolute; left:0; right:0; height:50%; overflow:hidden; }
.fh.up{ top:0; background:var(--card-a); transform-origin:50% 100%; }
.fh.down{ top:50%; background:var(--card-b); transform-origin:50% 0; }
.fh b{
  position:absolute; left:0; right:0; height:200%; display:flex; align-items:center; justify-content:center;
  font-family:'Orbitron',sans-serif; font-weight:900; font-size:calc(var(--ch) * 0.58em); color:var(--accent-ink);
  font-variant-numeric:tabular-nums;
}
.fh.up b{ top:0; }
.fh.down b{ top:-100%; }
:root[data-numfont="clean"] .fh b{ font-family:'Space Grotesk',sans-serif; font-weight:700; font-size:calc(var(--ch) * 0.68em); letter-spacing:-0.03em; }
.fc-s .fh b{ color:var(--text-dim); }
.fc-line{ position:absolute; left:0; right:0; top:calc(50% - var(--ch) * 0.012em); height:calc(var(--ch) * 0.024em); background:var(--bg); }
.fc-ampm{ position:absolute; display:flex; align-items:center; justify-content:center; }
.fc-ampm b{ font-size:0.14em; font-weight:800; letter-spacing:0.04em; color:var(--accent); }

/* Tear-off pads: a binding on top, the current sheet, the sheet being torn off (above it),
   a torn strip left under the binding, and two edges below for the sheets underneath. */
.tp{ position:absolute; }
.tp-edge{ position:absolute; top:calc(var(--ch) * 0.08em); border-radius:0 0 calc(var(--ch) * 0.04em) calc(var(--ch) * 0.04em); }
.tp-edge.e2{ left:4%; right:4%; bottom:0; background:var(--paper-edge2); }
.tp-edge.e1{ left:2%; right:2%; bottom:calc(var(--ch) * 0.012em); background:var(--paper-edge1); }
.tp-sheet{
  position:absolute; left:0; right:0; top:calc(var(--ch) * 0.08em); bottom:calc(var(--ch) * 0.024em);
  display:flex; flex-direction:column; align-items:center; justify-content:space-between;
  padding:calc(var(--ch) * 0.075em) calc(var(--ch) * 0.04em) calc(var(--ch) * 0.055em);
  border-radius:0 0 calc(var(--ch) * 0.04em) calc(var(--ch) * 0.04em);
  background:var(--paper); color:var(--paper-ink); transform-origin:0 0; overflow:hidden;
}
.tp-old{ z-index:1; box-shadow:0 calc(var(--ch) * 0.03em) calc(var(--ch) * 0.08em) rgba(0,0,0,0.35); }
.tp-head{ font-size:calc(var(--ch) * 0.066em); font-weight:700; letter-spacing:0.25em; padding-left:0.25em; color:var(--paper-red); }
.tp-num{ font-family:'Orbitron',sans-serif; font-weight:900; font-size:calc(var(--ch) * 0.42em); line-height:0.9; font-variant-numeric:tabular-nums; }
:root[data-numfont="clean"] .tp-num{ font-family:'Space Grotesk',sans-serif; font-weight:700; font-size:calc(var(--ch) * 0.52em); letter-spacing:-0.03em; }
.tp-foot{
  display:flex; align-items:center; justify-content:center; gap:0.35em; max-width:100%; min-height:1.2em;
  font-size:calc(var(--ch) * 0.064em * var(--tear-k, 1)); font-weight:600; color:color-mix(in srgb, var(--paper-ink) 70%, var(--paper));
}
.face[data-tear-size="s"]{ --tear-k:0.8; }
.face[data-tear-size="l"]{ --tear-k:1.3; }
.tp-txt{ overflow:hidden; text-overflow:ellipsis; min-width:0; }
.tp-ico:empty{ display:none; }
.tp-ico svg{ display:block; width:1.6em; height:1.6em; }
.tp-s .tp-sheet{ justify-content:center; padding:0; }
.tp-s .tp-head, .tp-s .tp-foot{ display:none; }
.tp-s .tp-num{ font-size:calc(var(--ch) * 0.46em); }
.tp-torn{
  position:absolute; left:0; right:0; top:calc(var(--ch) * 0.078em); height:calc(var(--ch) * 0.028em); z-index:2;
  background:var(--paper-edge1);
  clip-path:polygon(0 0, 100% 0, 100% 40%, 96% 90%, 92% 30%, 87% 80%, 83% 20%, 78% 70%, 73% 30%, 68% 100%, 63% 40%, 58% 80%, 53% 20%, 48% 90%, 43% 30%, 38% 70%, 33% 10%, 28% 80%, 23% 40%, 18% 100%, 13% 30%, 8% 80%, 4% 20%, 0 70%);
}
.tp-bind{
  position:absolute; left:0; right:0; top:0; height:calc(var(--ch) * 0.095em); z-index:3;
  display:flex; align-items:center; justify-content:space-around;
  border-radius:calc(var(--ch) * 0.025em); background:#2a2f3a; box-shadow:0 calc(var(--ch) * 0.01em) calc(var(--ch) * 0.03em) rgba(0,0,0,0.4);
}
.tp-bind i{ width:calc(var(--ch) * 0.045em); height:calc(var(--ch) * 0.045em); border-radius:50%; background:#0a0d12; box-shadow:inset 0 0 0 calc(var(--ch) * 0.01em) #8b94a3; }

/* The dial (an SVG in 1000 units per em). */
.dial{ position:absolute; left:0; top:0; width:100%; height:100%; overflow:visible; }
.dial-face{ fill:color-mix(in srgb, var(--text) 4%, var(--bg)); }
.dial .edge{ fill:none; stroke:var(--text-dim); stroke-opacity:0.4; stroke-width:4; }
:root[data-ring] .dial .edge{ display:none; }
.tick-minor{ fill:none; stroke:var(--text-dim); stroke-opacity:0.8; stroke-width:6; stroke-linecap:round; }
.face.tiny .inner-nums text:not(.five):not(.now), .inner-nums.crowded text:not(.five):not(.now){ display:none; }
.tick-major{ fill:none; stroke:var(--text); stroke-opacity:0.75; stroke-width:12; stroke-linecap:round; }
/* A small dial shows fewer hour numbers (fitted() in app.js): 12 · 3 · 6 · 9, or none, when the quarter ticks the numbers stood in for come back. */
.tick-quarter{ display:none; }
.face.nums-few .dial-nums text:not(.q){ display:none; }
.face.nums-none .dial-nums{ display:none; }
.face.nums-none .tick-quarter{ display:inline; }
.dial-nums text{ fill:var(--text); fill-opacity:0.85; font-weight:700; }
.inner-line{ fill:none; stroke:var(--accent2); stroke-opacity:0.35; stroke-width:4; }
.inner-nums text{ fill:var(--text-dim); font-weight:600; }
.inner-nums text.five{ fill:var(--accent2-ink); font-weight:700; }
.inner-nums text.now{ fill:var(--accent-ink); font-weight:800; }
.dial-window{ fill:var(--bg); stroke:var(--text-dim); stroke-opacity:0.55; stroke-width:5; }
.window-num{ fill:var(--accent); font-weight:900; }
.window-icon{ color:var(--accent2); }
/* Sunrise and sunset on the dial: the next one brightens and glows through its last hour. */
.sky-mark path{ fill:none; stroke:var(--accent); stroke-width:6; stroke-linecap:round; stroke-linejoin:round; }
.sky-mark path.sun-r{ fill:#ffd23f; }
.sky-mark path.sun-s{ fill:#ff6a13; }
@media (forced-colors: active){ .sky-mark path.sun-r, .sky-mark path.sun-s{ fill:CanvasText; } }
.sky-mark{ opacity:0.55; }
.sky-mark.next{ opacity:calc(0.55 + 0.45 * var(--near, 0)); filter:drop-shadow(0 0 calc(var(--near, 0) * 8px) var(--accent)); }
:root[data-numfont="clean"] .window-num{ font-weight:700; }
.hand{ stroke-linecap:round; }
.hand-h{ stroke:var(--accent); stroke-width:44; }
.hand-m{ stroke:var(--accent); stroke-width:26; }
.hand-s{ stroke:var(--accent2); stroke-width:9; }
.dial-cap{ fill:var(--accent); }
.dial-pin{ fill:var(--bg); }

/* The crossword, and the minute markers under it (or under the words). */
.wg{
  position:absolute; left:0; top:0;   /* (size set in em by the face: a crossword, a letter in each 0.1em cell) */
  --grid-lit:var(--accent-ink);
}
.wg[data-lit="blue"]{ --grid-lit:var(--accent2-ink); }
.wg[data-lit="white"]{ --grid-lit:var(--text); }
/* A crossword cell: a small square with its letter, dim until a word that tells the time lights it. */
.gl{
  position:absolute; width:1.48em; height:1.48em; transform:translate(-50%, -50%);   /* (the font is 0.062 of the face's em, so 1.48em is 0.092em of it) */
  display:flex; align-items:center; justify-content:center; border-radius:0.2em;
  box-shadow:inset 0 0 0 0.07em currentColor;
  line-height:1; font-size:0.062em; font-weight:700; color:var(--text-dim); opacity:0.2;
}
.wg[data-unlit="hidden"] .gl:not(.on){ opacity:0; }
.gl.on{ color:var(--grid-lit); opacity:1; text-shadow:0 0 0.4em color-mix(in srgb, var(--grid-lit) 45%, transparent); }
.marks{ position:absolute; left:0; bottom:0; height:0.075em; display:flex; align-items:center; gap:0.035em; }
.wg ~ .marks{ right:0; justify-content:center; }
.mk{ position:relative; display:block; flex-shrink:0; overflow:hidden; background:color-mix(in srgb, var(--text-dim) 28%, transparent); }
.mk b{ position:absolute; left:0; right:0; bottom:0; height:0; background:var(--accent); }
.marks-dots .mk{ width:0.045em; height:0.045em; border-radius:50%; }
.marks-bars .mk{ width:0.09em; height:0.026em; border-radius:0.013em; }
.marks-diamonds .mk{ width:0.038em; height:0.038em; margin:0 0.006em; transform:rotate(45deg); }
.marks-barrels .mk{ width:0.042em; height:0.068em; border-radius:0.014em; background:transparent; box-shadow:inset 0 0 0 0.005em color-mix(in srgb, var(--accent) 55%, transparent); }
.mk-arc{ width:0.075em; height:0.075em; }
/* Rings: one small ring per minute, its line going round as the seconds pass. */
.marks-rings .mk{ width:0.05em; height:0.05em; background:none; overflow:visible; }
.mk-ring{ display:block; width:100%; height:100%; }
.marks-rings .mk.on .mk-track{ stroke:var(--accent); }
.mk-track{ fill:none; stroke:color-mix(in srgb, var(--text-dim) 35%, transparent); stroke-width:12; }
.mk-fill{ fill:none; stroke:var(--accent); stroke-width:12; stroke-linecap:round; stroke-dasharray:0 100; }

/* Unix time: ten digits in cells of one width (--cell), in the digits' font. The face is clipped
   like the others, except here: the breakdown tooltip opens outside it (the one the date row's
   Unix time has, see above). */
:root[data-face="unix"] .face{ overflow:visible; }
.ux-num{
  position:absolute; left:0; top:0; width:100%; display:flex; justify-content:center; align-items:flex-start;
  font-family:'Orbitron',sans-serif; font-weight:900; letter-spacing:0; line-height:1; color:var(--accent);
  text-box:trim-both cap alphabetic; cursor:help;
}
:root[data-numfont="clean"] .ux-num{ font-family:'Space Grotesk',sans-serif; font-weight:700; }
.ux-d{ display:block; font-style:normal; width:var(--cell); text-align:center; flex:none; }
@supports not (text-box: trim-both cap alphabetic){ .ux-num{ line-height:0.76; } }
.ux-l{ position:absolute; left:0; width:100%; text-align:center; font-weight:700; line-height:1.3; color:var(--text); }
.ux-l3{ font-weight:500; color:var(--text-dim); }
.ux-num[data-tip]:hover::after{
  content:attr(data-tip); position:absolute; left:var(--tip-x, 0px); bottom:calc(100% + 0.6rem); z-index:5;
  width:max-content; max-width:min(24rem, calc(100vw - 1rem)); padding:0.6rem 0.8rem; border-radius:0.6rem;
  background:var(--bg-panel); border:1px solid var(--divider); box-shadow:0 0.3rem 1rem var(--shadow);
  font-family:'Space Grotesk', system-ui, sans-serif; font-size:0.85rem; font-weight:500; letter-spacing:0; line-height:1.45;
  white-space:pre-line; color:var(--text); text-align:left; text-box:normal;
}
.ux-num.tip-below[data-tip]:hover::after{ bottom:auto; top:calc(100% + 0.6rem); }
/* Just the words. */
.wl{ position:absolute; left:0; font-weight:700; line-height:1; color:var(--text); letter-spacing:-0.01em; }
.wl1{ color:var(--text-dim); letter-spacing:0.03em; }
.wl .hour, .wl.hour{ color:var(--accent); }

/* Graffiti: a wall (a brick pattern, or concrete), and the time sprayed on it. On a wall the
   paint keeps its bright colours whatever the theme. */
.gwall{ position:absolute; inset:0; border-radius:0.03em; }
.gwall-bricks{
  background-color:#17110f;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='96' height='48'%3E%3Crect width='96' height='48' fill='%2317110f'/%3E%3Crect x='2' y='2' width='92' height='20' rx='2' fill='%232a1f1b'/%3E%3Crect x='-46' y='26' width='92' height='20' rx='2' fill='%23281d19'/%3E%3Crect x='50' y='26' width='92' height='20' rx='2' fill='%232c211c'/%3E%3C/svg%3E");
  background-size:0.2em 0.1em;
}
.gwall-concrete{
  background-color:#55595e;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.75' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0  0 0 0 0 0  0 0 0 0 0  0 0 0 0.45 0'/%3E%3C/filter%3E%3Crect width='240' height='240' filter='url(%23n)'/%3E%3C/svg%3E"),
    linear-gradient(160deg, rgba(255,255,255,0.06), rgba(0,0,0,0.22));
  background-size:0.5em 0.5em, 100% 100%;
}
.gwall-none{ display:none; }
.gw{ position:absolute; white-space:nowrap; font-family:'Permanent Marker','Space Grotesk',sans-serif; font-weight:400; line-height:1.1; transform-origin:0 50%; }
.gw.p0{ color:var(--accent); } .gw.p1{ color:var(--accent2); } .gw.p2{ color:var(--fill-pink); }
.gwall:not(.gwall-none) ~ .gw.p0{ color:#ffb454; } .gwall:not(.gwall-none) ~ .gw.p1{ color:#5ec9f1; } .gwall:not(.gwall-none) ~ .gw.p2{ color:#ff7aa8; }
.gwall:not(.gwall-none) ~ .gw{ text-shadow:0 0 0.12em color-mix(in srgb, currentColor 50%, transparent); }
.drip{ position:absolute; top:85%; width:0.05em; border-radius:0 0 0.05em 0.05em; background:currentColor; transform-origin:top; opacity:0.85; }
.gsec{ position:absolute; right:2.5%; bottom:3%; font-family:'Permanent Marker','Space Grotesk',sans-serif; font-weight:400; font-size:0.12em; color:var(--text-dim); }
.gwall:not(.gwall-none) ~ .gsec{ color:#c9ced6; }

/* Chalkboard. With no board, the chalk writes on the app's own background. */
.face{ --chalk:#eef0ea; }
.face[data-ink="colour"]{ --chalk:#ffd08a; }
.board{
  position:absolute; inset:0; border-radius:0.02em; border:0.028em solid #6b4f36;
  background:radial-gradient(ellipse at 30% 35%, #29342e 0%, #1c2420 65%, #171d1a 100%);
  box-shadow:inset 0 0 0.12em rgba(0,0,0,0.6);
}
.board-black{ background:radial-gradient(ellipse at 30% 35%, #2a2c30 0%, #17181b 70%); }
.board-none{ display:none; }
.board-none ~ .cw{ --chalk:var(--text); }
.face[data-ink="colour"] .board-none ~ .cw{ --chalk:var(--accent); }
.cw{ position:absolute; inset:0; }
.cl{
  position:absolute; left:0; right:0; text-align:center; font-family:Caveat,'Space Grotesk',sans-serif; font-weight:700; line-height:1.12;
  color:var(--chalk); text-shadow:0 0 0.03em color-mix(in srgb, var(--chalk) 55%, transparent);
}
.eraser{
  position:absolute; z-index:2; width:0.26em; height:0.13em; border-radius:0.02em; transform:rotate(-8deg);
  background:linear-gradient(#9a7652 0 56%, #4b4e52 56% 100%); box-shadow:0 0.03em 0.06em rgba(0,0,0,0.5);
}
.smudge{ position:absolute; left:0.1em; right:0.1em; top:0.1em; height:0.7em; border-radius:0.2em; background:rgba(238,240,234,0.07); filter:blur(0.04em); opacity:0; }
.chalk-sec{ position:absolute; left:0; top:0; width:100%; height:100%; }
.chalk-line{ fill:none; stroke:#ffb454; stroke-opacity:0.85; stroke-width:16; stroke-linecap:round; stroke-dasharray:0 100; }
.tally{ fill:none; stroke:var(--chalk); stroke-opacity:0.85; stroke-width:12; stroke-linecap:round; }
.board-none ~ .chalk-sec .tally{ stroke:var(--text); }

/* Word by word (pointing at a word face): one huge word at a time over the dimmed face. */
.face.wbw-on > :not(.wbw){ opacity:0.25; }
.wbw{ position:absolute; inset:0; display:flex; align-items:center; justify-content:center; pointer-events:none; }
.wbw span{ font-weight:700; color:var(--text); line-height:1; }
.wbw span.hour{ color:var(--accent); }

/* The ring's finish at 12 (drawn by app.js in hundredths of an em), and what it does when a
   timer gets there (Motion: Full; nothing flashes more than about once a second). */
.bezel .fm-tri{ fill:var(--text-dim); fill-opacity:0.75; }
.fm-pole{ fill:none; stroke:var(--text-dim); stroke-width:1.5px; vector-effect:non-scaling-stroke; stroke-linecap:round; }
.fm-light{ fill:var(--text); fill-opacity:0.85; }
.fm-dark{ fill:var(--bg); }
.fm-tape{ stroke:var(--fill-pink); stroke-width:2.2px; vector-effect:non-scaling-stroke; stroke-linecap:round; }
.fm-post{ fill:var(--text-dim); }
.fm-trophy{ fill:none; stroke:var(--accent); stroke-width:1.4px; vector-effect:non-scaling-stroke; stroke-linecap:round; stroke-linejoin:round; }
.fm-spark path{ fill:none; stroke:var(--accent); stroke-width:1.5px; vector-effect:non-scaling-stroke; stroke-linecap:round; opacity:0; }
.sec-arc{ fill:none; stroke:var(--accent); stroke-width:2.5px; vector-effect:non-scaling-stroke; stroke-linecap:round; }
:root[data-motion="full"] .ring.arrive .fm-flag{ animation:fm-wave 0.35s ease-in-out 6 alternate; transform-box:fill-box; transform-origin:0 50%; }
:root[data-motion="full"] .ring.arrive .fm-banner{ animation:fm-glow 0.8s ease-in-out 3; }
:root[data-motion="full"] .ring.arrive .fm-check{ animation:fm-blink 0.8s ease-in-out 3; }
:root[data-motion="full"] .ring.arrive .fm-tape-a{ animation:fm-snap-a 2.4s ease-out; transform-box:fill-box; transform-origin:50% 0; }
:root[data-motion="full"] .ring.arrive .fm-tape-b{ animation:fm-snap-b 2.4s ease-out; transform-box:fill-box; transform-origin:50% 100%; }
:root[data-motion="full"] .ring.arrive .fm-trophy{ animation:fm-hop 0.6s ease-out 3; }
:root[data-motion="full"] .ring.arrive .fm-spark path{ animation:fm-spark 0.9s ease-out 2; transform-box:fill-box; transform-origin:50% 50%; }
@keyframes fm-wave{ from{ transform:skewY(-14deg) scaleX(0.92); } to{ transform:skewY(12deg); } }
@keyframes fm-glow{ 50%{ filter:drop-shadow(0 0 2px var(--accent)); } }
@keyframes fm-blink{ 50%{ opacity:0.35; } }
@keyframes fm-snap-a{ 0%{ transform:none; } 15%, 75%{ transform:rotate(-75deg); opacity:1; } 90%{ transform:rotate(-75deg); opacity:0; } 100%{ transform:none; opacity:1; } }
@keyframes fm-snap-b{ 0%{ transform:none; } 15%, 75%{ transform:rotate(75deg); opacity:1; } 90%{ transform:rotate(75deg); opacity:0; } 100%{ transform:none; opacity:1; } }
@keyframes fm-hop{ 40%{ transform:translateY(-3px); } }
@keyframes fm-spark{ 0%{ opacity:0; transform:scale(0.5); } 30%{ opacity:1; } 100%{ opacity:0; transform:scale(1.6); } }

/* Settings > Style: the faces as tiles, choices in a grid, the finish marks as icons. */
.face-tiles{ display:grid; grid-template-columns:repeat(3, minmax(0, 1fr)); gap:0.3rem; }
.face-tiles button{
  display:flex; flex-direction:column; align-items:center; gap:0.25rem; min-width:0;
  padding:0.5rem 0.1rem 0.4rem; background:var(--bg); border:1px solid var(--divider); border-radius:0.6rem;
  color:var(--text-dim); font-size:0.72rem; font-weight:600; cursor:pointer;
}
.face-tiles button svg{ width:1.5rem; height:1.5rem; }
.face-tiles button:hover, .choices button:hover, .finish-tiles button:hover{ border-color:var(--text-dim); }
.face-tiles button[aria-pressed="true"], .choices button[aria-pressed="true"], .finish-tiles button[aria-pressed="true"]{
  border-color:var(--accent); color:var(--text); background:color-mix(in srgb, var(--accent) 14%, var(--bg));
}
.face-tiles button[aria-pressed="true"] svg, .finish-tiles button[aria-pressed="true"] svg{ color:var(--accent); }
.choices{ display:grid; grid-template-columns:repeat(2, minmax(0, 1fr)); gap:0.3rem; }
.choices.three{ grid-template-columns:repeat(3, minmax(0, 1fr)); }
.choices.four{ grid-template-columns:repeat(4, minmax(0, 1fr)); }
.features.ring-tiles{ grid-template-columns:repeat(3, minmax(0, 1fr)); }
.features.wx-tiles{ grid-template-columns:repeat(7, minmax(0, 1fr)); gap:0.2rem; }
.wx-tiles button{ font-size:0.7rem; }
.wx-group + .wx-group{ margin-top:0.55rem; }
.wx-group-label{ display:block; margin-bottom:0.3rem; font-size:0.78rem; font-weight:600; color:var(--text-dim); }
.features button:disabled{ opacity:0.35; cursor:default; }
.line-tiles{ grid-template-columns:repeat(5, minmax(0, 1fr)); }
.choices button{
  min-width:0; padding:0.4rem 0.3rem; border:1px solid var(--divider); border-radius:0.45rem; background:var(--bg);
  color:var(--text-dim); font-size:0.78rem; cursor:pointer;
}
.finish-tiles{ display:grid; grid-template-columns:repeat(7, minmax(0, 1fr)); gap:0.25rem; }
.finish-tiles button{
  display:flex; justify-content:center; min-width:0; padding:0.3rem 0; border:1px solid var(--divider); border-radius:0.45rem;
  background:var(--bg); color:var(--text-dim); cursor:pointer;
}
.finish-tiles button svg{ width:1.3rem; height:1.3rem; }
/* Style tab headings: the chosen style's own options, then those for every style. */
.style-head{ display:block; margin-top:0.2rem; padding-top:0.55rem; border-top:1px solid var(--divider); font-size:0.72rem; font-weight:700; letter-spacing:0.06em; text-transform:uppercase; color:var(--text-dim); }
.style-head:empty{ display:none; }
.keys-note{ font-size:0.85em; color:var(--text-dim); }

/* Windows contrast themes: the system's colours replace ours. Switches and the chosen option
   in each group keep a visible state, and the dial and ring draw in the text colour. */
@media (forced-colors: active){
  .switch, .switch::after{ forced-color-adjust:none; }
  .switch{ border:1px solid ButtonText; background:ButtonFace; }
  .switch::after{ background:ButtonText; }
  .switch[aria-checked="true"]{ background:Highlight; }
  .switch[aria-checked="true"]::after{ background:HighlightText; }
  .seg button.active, .choices button[aria-pressed="true"], .face-tiles button[aria-pressed="true"],
  .finish-tiles button[aria-pressed="true"], .tabs button[aria-selected="true"], .features button[aria-pressed="true"],
  .date-formats button[aria-pressed="true"], .alarm-days button[aria-pressed="true"]{ forced-color-adjust:none; background:Highlight; color:HighlightText; }
  .hand, .tick-major, .tick-minor, .dial .edge, .inner-line, .track-line, .sec-arc{ stroke:CanvasText; }
  .dial-face, .dial-pin{ fill:Canvas; }
  .dial-cap, .dial-nums text, .inner-nums text, .window-num, .bezel .fm-tri{ fill:CanvasText; }
  .gl:not(.on){ opacity:0.35; }
  .gl.on{ color:Highlight; text-shadow:none; }
}

/* ---------- looks: the gallery of ready-made looks ---------- */
/* A grid of pictures that scrolls in its own box; pointing at one shows it twice as big in a
   layer above everything (.look-zoom), "i" and the play button pop up a note (.look-pop). */
.looks-sheet{ z-index:26; }
.looks-card{
  width:min(74rem, calc(100vw - 2rem)); max-height:calc(100vh - 2rem); max-height:calc(100dvh - 2rem);
  display:flex; flex-direction:column; gap:1rem; font-size:16px;
}
.looks-sheet:not(.drawer) .looks-card{ width:min(40rem, calc(100vw - 2rem)); }
.looks-head{ display:flex; justify-content:space-between; align-items:flex-start; gap:1rem; text-align:left; }
.looks-head .sheet-title{ max-width:none; font-size:2rem; }
.looks-head .sheet-sub{ max-width:46em; margin-top:0.35rem; font-size:1rem; }
.looks-close{
  flex-shrink:0; width:2.4rem; height:2.4rem; border-radius:50%; cursor:pointer;
  background:var(--bg-panel); border:1px solid var(--divider); color:var(--text); font-size:1.5rem; line-height:1;
}
.looks-grid{
  display:grid; grid-template-columns:repeat(auto-fill, minmax(14rem, 1fr)); gap:1.1rem 1.2rem;
  overflow-y:auto; overscroll-behavior:contain; padding:0.4rem 0.4rem 0.8rem; min-height:0;
}
.look{ margin:0; display:flex; flex-direction:column; gap:0.55rem; min-width:0; }
.look-shot{
  aspect-ratio:16 / 10; border-radius:0.8rem; overflow:hidden; cursor:zoom-in;
  background:var(--bg-panel); border:1px solid var(--divider); box-shadow:0 0.4rem 1.2rem var(--shadow);
  transition:transform 0.2s, border-color 0.2s;
}
.look-shot:hover{ transform:translateY(-3px); border-color:var(--accent2); }
.look-shot img{ display:block; width:100%; height:100%; object-fit:cover; }
.look figcaption{ display:flex; align-items:center; gap:0.5rem; }
.look-name{ flex:1; min-width:0; text-align:left; font-weight:700; color:var(--text); }
.look-i{
  width:1.9rem; height:1.9rem; flex-shrink:0; border-radius:50%; cursor:help;
  background:none; border:1.5px solid var(--divider); color:var(--text-dim); font:italic 700 0.95rem Georgia, 'Times New Roman', serif;
}
.look-i:hover, .look-i:focus-visible{ border-color:var(--accent2); color:var(--accent2); }
.look-go{
  width:2.4rem; height:2.4rem; flex-shrink:0; border-radius:50%; cursor:pointer; display:grid; place-items:center;
  background:var(--accent); color:var(--bg); border:none; transition:transform 0.15s;
}
.look-go svg{ width:1.15rem; height:1.15rem; margin-left:2px; }
.look-go:hover, .look-go:focus-visible{ transform:scale(1.12); }
.look-zoom{
  position:fixed; z-index:40; pointer-events:none; overflow:hidden; border-radius:0.9rem;
  border:2px solid var(--accent2); box-shadow:0 1rem 3rem var(--shadow); background:var(--bg-panel);
  animation:look-zoom 0.18s ease-out;
}
.look-zoom img{ display:block; width:100%; height:100%; object-fit:cover; }
@keyframes look-zoom{ from{ opacity:0; transform:scale(0.6); } }
:root[data-motion="off"] .look-zoom, :root[data-motion="calm"] .look-zoom{ animation:none; }
.look-pop{
  position:fixed; z-index:41; max-width:17rem; padding:0.6rem 0.8rem; pointer-events:none; text-align:left;
  border-radius:0.7rem; background:var(--bg-panel); border:1px solid var(--divider); box-shadow:0 0.4rem 1.2rem var(--shadow);
  color:var(--text); font-size:0.88rem; line-height:1.4;
}
.look-pop ul{ margin:0.3rem 0 0; padding-left:1.1rem; color:var(--text-dim); }
.look-pop .quip{ font-weight:700; color:var(--accent-ink); }
/* Wide windows: the gallery is a drawer down the right edge, one look per row, scrolling inside,
   and the clock stays visible (and its normal size) to its left while a look is previewed on it
   (the welcome card, if it opened the drawer, steps aside). Narrower, it stays the full-screen
   list above, with no live preview. */
.looks-sheet .sub-live, .looks-sheet.drawer .sub-zoom{ display:none; }
.looks-sheet.drawer .sub-live{ display:inline; }
#looks.looks-sheet.drawer{
  inset:0 0 0 auto; width:clamp(21.25rem, 28vw, 26rem); justify-content:stretch; align-items:stretch;
  background:var(--bg-panel); border-left:1px solid var(--divider); box-shadow:-0.5rem 0 1.5rem var(--shadow);
}
.looks-sheet.drawer .looks-card{ width:100%; max-height:none; height:100%; box-sizing:border-box; padding:1rem 0.9rem 0.6rem; gap:0.7rem; }
.looks-sheet.drawer .looks-head .sheet-title{ font-size:1.5rem; }
.looks-sheet.drawer .looks-head .sheet-sub{ font-size:0.9rem; margin-top:0.3rem; }
.looks-sheet.drawer .looks-grid{ grid-template-columns:1fr; flex:1; }
body.looks-drawer #welcome{ visibility:hidden; }
.look.peeking .look-shot{ box-shadow:0 0 0 2px var(--accent2), 0 0.4rem 1.2rem var(--shadow); border-color:var(--accent2); }
.look-toast{
  position:fixed; z-index:35; left:50%; bottom:max(1rem, env(safe-area-inset-bottom, 0px)); transform:translateX(-50%);
  display:flex; align-items:center; gap:0.5rem; max-width:calc(100vw - 2rem); padding:0.5rem 0.6rem 0.5rem 1rem;
  border-radius:999px; background:var(--bg-panel); border:1px solid var(--divider); box-shadow:0 0.4rem 1.2rem var(--shadow);
  color:var(--text); font-size:0.9rem;
}
.look-toast button{ background:none; border:none; cursor:pointer; font:inherit; font-weight:700; color:var(--text-dim); padding:0.2rem 0.5rem; }
.look-toast #look-undo{ color:var(--accent); }
.looks-strip, .looks-btn{
  display:inline-flex; align-items:center; gap:0.8rem; cursor:pointer; font:inherit; font-weight:600;
  background:none; border:1px dashed var(--divider); border-radius:0.8rem; padding:0.45rem 0.9rem; color:var(--accent2-ink);
}
.looks-strip:hover, .looks-btn:hover, .looks-strip:focus-visible, .looks-btn:focus-visible{ border-style:solid; border-color:var(--accent2); }
.looks-btn{ width:100%; justify-content:center; font-size:0.85rem; }
.strip-imgs{ display:flex; }
.strip-imgs img{ width:3.2em; height:2em; object-fit:cover; border-radius:0.3em; border:1.5px solid var(--bg-panel); margin-left:-0.9em; box-shadow:0 0.1em 0.3em var(--shadow); }
.strip-imgs img:first-child{ margin-left:0; }
@media (max-width:520px){ .looks-head .sheet-title{ font-size:1.5rem; } .looks-grid{ grid-template-columns:repeat(auto-fill, minmax(11rem, 1fr)); } }

/* Footer links are at least 24px tall to click or tap (WCAG 2.2 target size). */
.panel-foot a, .panel-foot .foot-links a{ display:inline-flex; align-items:center; min-height:24px; }

/* ---------- the bottom corners ---------- */
/* Accessibility (left) and keyboard shortcuts (right), like the icons at the top. The page
   keeps room for them (data-corners, set by fitLayout when the window has room). */
.corners .tool{ position:fixed; z-index:20; bottom:max(0.4rem, env(safe-area-inset-bottom, 0px)); display:none; }
.corners .corner-left{ left:max(0.4rem, env(safe-area-inset-left, 0px)); }
/* A label for the left icon (the right one shows the shortcuts banner): "Accessibility" and its
   key, above the icon (a sibling of the button, so the button's own dimming doesn't fade it) when it is pointed at or focused from the keyboard. Doesn't open the menu. */
.corner-tip{
  position:fixed; z-index:21; left:max(0.4rem, env(safe-area-inset-left, 0px)); bottom:calc(max(0.4rem, env(safe-area-inset-bottom, 0px)) + 2.4rem); display:flex; align-items:center; gap:0.4em;
  padding:0.3rem 0.6rem; border-radius:0.6rem; white-space:nowrap; pointer-events:none;
  background:var(--bg-panel); border:1px solid var(--divider); box-shadow:0 2px 12px var(--shadow);
  color:var(--text); font-size:0.8rem; font-weight:600; opacity:0; visibility:hidden;
  transition:opacity 0.15s 0.3s, visibility 0s 0.45s;
}
.corner-tip kbd[hidden]{ display:none; }
.corner-tip kbd{ min-width:1.5em; padding:0.05em 0.35em; font-size:0.9em; }
.corner-left:hover + .corner-tip, .corner-left:focus-visible + .corner-tip{ opacity:1; visibility:visible; transition-delay:0.3s, 0.3s; }
.corner-left:focus-visible + .corner-tip{ transition-delay:0s; }
:root[data-motion="off"] .corner-tip{ transition:none; }
:root[data-contrast="high"] .corner-tip{ border-color:var(--text); }
.corners .corner-right{ right:max(0.4rem, env(safe-area-inset-right, 0px)); }
:root[data-corners] .corners .tool{ display:flex; }
:root[data-corners] .app{ padding-bottom:2.7rem; }
/* "Click a part to change it": the parts show they can be clicked; the setting it opens
   at pulses twice. */
:root[data-quickset] #time, :root[data-quickset] #now, :root[data-quickset] #date, :root[data-quickset] .info > *,
:root[data-quickset] #forecast, :root[data-quickset] #extras{ cursor:pointer; }
:root[data-quickset] #now:hover, :root[data-quickset] #date:hover, :root[data-quickset] .info > *:hover, :root[data-quickset] #forecast:hover{
  outline:1px dashed color-mix(in srgb, var(--accent2) 55%, transparent); outline-offset:0.25em; border-radius:0.3em;
}
.pulse{ border-radius:0.5rem; animation:setting-pulse 0.85s ease-in-out 3; }
@keyframes setting-pulse{
  0%, 100%{ box-shadow:0 0 0 0 transparent; background-color:transparent; }
  45%{ box-shadow:0 0 0 0.25rem color-mix(in srgb, var(--accent2) 45%, transparent); background-color:color-mix(in srgb, var(--accent2) 14%, transparent); }
}
:root[data-motion="off"] .pulse{ animation:none; box-shadow:0 0 0 0.2rem color-mix(in srgb, var(--accent2) 45%, transparent); }
/* The accessibility report button is a link (it opens an email draft), dressed as the others. */
a.add-btn{ display:block; text-align:center; text-decoration:none; color:var(--text); border:1px dashed var(--divider); border-radius:0.55rem; }
a.add-btn:hover, a.add-btn:focus-visible{ border-color:var(--accent2); }
.panel .hint a{ color:var(--accent2); }

/* ---------- opening animation ----------
   app.js sets data-intro (full or calm) for the first moments after the app opens. Only
   opacity, transforms and masks move, never a size, and the targets are containers, so every
   clock style gets it. Full: the ring and any dial draw themselves round (a conic mask), the
   time settles in, then the weather fades up. Calm: one short fade. */
@property --intro-a{ syntax:"<angle>"; inherits:false; initial-value:360deg; }
@keyframes intro-draw{ from{ --intro-a:0deg; } to{ --intro-a:360deg; } }
@keyframes intro-settle{ from{ opacity:0; transform:translateY(0.1em) scale(0.97); } to{ opacity:1; transform:none; } }
@keyframes intro-fade{ from{ opacity:0; } to{ opacity:1; } }
:root[data-intro="full"] .time:not(.measure) > :not(.ring):not(.sr-only){ animation:intro-settle 0.7s cubic-bezier(0.2, 0.8, 0.3, 1) 0.45s both; }
:root[data-intro="full"] .time:not(.measure) .ring .track, :root[data-intro="full"] .face .dial{
  -webkit-mask-image:conic-gradient(#000 var(--intro-a), transparent var(--intro-a)); mask-image:conic-gradient(#000 var(--intro-a), transparent var(--intro-a));
  animation:intro-draw 1.1s ease-in-out both;
}
:root[data-intro="full"] .band, :root[data-intro="full"] .timers{ animation:intro-fade 0.8s ease-out 0.8s both; }
:root[data-intro="calm"] .time:not(.measure), :root[data-intro="calm"] .band{ animation:intro-fade 0.6s ease-out both; }

/* The welcome card's unticked "keep the screen on" choice. */
.welcome-awake{ display:flex; align-items:center; justify-content:center; gap:0.5em; font-size:0.95em; color:var(--text); cursor:pointer; }
.welcome-awake input{ width:1.1em; height:1.1em; margin:0; accent-color:var(--accent-ink); cursor:pointer; flex:none; }
.welcome-awake span{ text-align:left; }
/* ---------- chained timers (Settings > Timers: Then start) ---------- */
.preset-then{ grid-column:1 / -1; display:flex; flex-wrap:wrap; align-items:center; gap:0.3rem 0.5rem; padding-inline-start:2.45rem; color:var(--text-dim); }
.preset-then select{
  flex:1 1 8rem; min-width:0; background:var(--bg); border:1px solid var(--divider); color:var(--text);
  border-radius:0.4rem; padding:0.3rem 0.4rem; font-family:inherit; font-size:0.78rem;
}
.preset-then select:focus-visible{ outline:2px solid var(--accent2); outline-offset:1px; }
.preset-then .hint{ flex-basis:100%; }

/* ---------- screen fill: bubbles ----------
   Bubbles: the level rises as with "Fills up"; the bubbles rise through it. Still with Motion:
   Off (each sits at its own height); Calm keeps the first four, slower. */
.fill.bubbles .fill-level{ right:0; border-top:2px solid color-mix(in srgb, var(--fill-c) var(--fill-edge), transparent); overflow:hidden; }
.fill.bubbles .fill-level i{
  position:absolute; left:var(--x); bottom:var(--y, 0); width:var(--s); height:var(--s); border-radius:50%;
  border:1.5px solid color-mix(in srgb, var(--fill-c) var(--fill-edge), transparent);
  background:color-mix(in srgb, var(--fill-c) calc(var(--fill-a) * 0.8), transparent);
}
:root[data-motion="full"] .fill.bubbles:not(.paused) .fill-level i{ animation:bubble-up var(--d) linear var(--w) infinite; }
:root[data-motion="calm"] .fill.bubbles:not(.paused) .fill-level i{ animation:bubble-up calc(var(--d) * 2) linear var(--w) infinite; }
:root[data-motion="calm"] .fill.bubbles .fill-level i:nth-child(n+5){ display:none; }
@keyframes bubble-up{ from{ bottom:calc(0% - 3rem); opacity:0; } 8%{ opacity:1; } 90%{ opacity:1; } to{ bottom:100%; opacity:0; } }
/* ---------- click-to-change bubbles ---------- */
/* A small settings popover next to the part that was clicked (app.js "click-to-change
   bubbles"); its arrow points at the click. Below the sheets (z-index 25) so a time's-up card
   or Settings is never covered by it. */
.bubble{
  position:fixed; z-index:24; box-sizing:border-box;
  width:min(19rem, calc(100vw - 16px));
  padding:0.6rem 0.75rem 0.75rem; font-size:15px; text-align:left;
  background:var(--bg-panel); color:var(--text); border:1px solid var(--divider); border-radius:0.8rem;
  box-shadow:0 0.8rem 2.2rem var(--shadow);
}
.bubble[hidden]{ display:none; }
.bubble-head{ display:flex; align-items:center; justify-content:space-between; gap:0.5rem; margin-bottom:0.5rem; }
.bubble-title{ font-weight:700; color:var(--accent-ink); }
.bubble-all{
  display:flex; align-items:center; justify-content:center; width:2rem; height:2rem; padding:0; cursor:pointer;
  background:none; border:1px solid var(--divider); border-radius:50%; color:var(--text-dim);
}
.bubble-all svg{ width:1.1rem; height:1.1rem; }
.bubble-all:hover, .bubble-all:focus-visible{ border-color:var(--accent2); color:var(--accent2); }
.bubble-body{
  display:flex; flex-direction:column; gap:0.6rem;
  padding:3px; margin:-3px; max-height:calc(100vh - 6.5rem); max-height:calc(100dvh - 6.5rem); overflow-y:auto;   /* (the arrow sticks out, so the box itself can't scroll) */
}
.bubble-group{ display:flex; flex-direction:column; gap:0.3rem; }
.bubble-label{ font-size:0.8rem; color:var(--text-dim); }
.bubble button{ font:inherit; }
.bubble-seg{ display:flex; border:1px solid var(--divider); border-radius:0.5rem; overflow:hidden; }
.bubble-seg button{ flex:1; background:none; border:none; color:var(--text-dim); font-size:0.85rem; padding:0.4rem 0.5rem; cursor:pointer; }
.bubble-seg button[aria-pressed="true"]{ background:var(--accent-ink); color:var(--bg); font-weight:700; }
.bubble-chips{ display:flex; flex-wrap:wrap; gap:0.3rem; }
.bubble-chips button{
  background:none; border:1px solid var(--divider); border-radius:0.5rem; color:var(--text-dim);
  font-size:0.85rem; padding:0.35rem 0.6rem; cursor:pointer;
}
.bubble-chips button[aria-pressed="true"]{ border-color:var(--accent2); color:var(--text); background:color-mix(in srgb, var(--accent2) 14%, var(--bg)); }
.bubble-seg button:hover, .bubble-chips button:hover{ color:var(--text); }
.bubble-seg button[aria-pressed="true"]:hover{ color:var(--bg); }
.bubble-seg button:focus-visible, .bubble-chips button:focus-visible, .bubble-here:focus-visible, .bubble .switch:focus-visible, .bubble input:focus-visible{
  outline:2px solid var(--accent2); outline-offset:1px;
}
.bubble-switch{ display:flex; align-items:center; justify-content:space-between; gap:0.6rem; font-size:0.9rem; }
.bubble input[type="text"]{
  width:100%; min-width:0; box-sizing:border-box; background:var(--bg); border:1px solid var(--divider); color:var(--text);
  border-radius:0.4rem; padding:0.45rem 0.55rem; font-family:inherit; font-size:0.9rem; text-align:start;
}
.bubble .loc-list{ display:flex; flex-direction:column; gap:0.2rem; }
.bubble .loc-list button{ text-align:start; width:100%; color:var(--text); background:none; border:none; font-size:0.85rem; padding:0.3rem 0.3rem; cursor:pointer; border-radius:0.3rem; overflow-wrap:anywhere; }
.bubble .loc-list button:hover{ background:var(--divider); }
.bubble .hint{ font-size:0.75rem; color:var(--text-dim); }
.bubble .hint:empty{ display:none; }
.bubble-here{
  align-self:flex-start; background:none; border:1px solid var(--divider); border-radius:0.5rem; color:var(--text);
  font-size:0.85rem; padding:0.4rem 0.7rem; cursor:pointer;
}
.bubble-here:hover{ border-color:var(--accent2); }
/* The arrow: a rotated square on the edge facing the click (data-side: where the bubble sits
   relative to it; top = under the click). */
.bubble-arrow{
  position:absolute; width:12px; height:12px; box-sizing:border-box; background:var(--bg-panel);
  border:1px solid var(--divider); transform:translate(-50%, -50%) rotate(45deg);
}
.bubble[data-side="top"] .bubble-arrow{ top:0; border-right:none; border-bottom:none; }
.bubble[data-side="bottom"] .bubble-arrow{ top:100%; border-left:none; border-top:none; }
.bubble[data-side="left"] .bubble-arrow{ left:0; border-right:none; border-top:none; }
.bubble[data-side="right"] .bubble-arrow{ left:100%; border-left:none; border-bottom:none; }
:root[data-motion="full"] .bubble:not([hidden]){ animation:bubble-in 0.16s ease-out both; }
@keyframes bubble-in{ from{ opacity:0; transform:translateY(4px) scale(0.96); } }
@media (forced-colors:active){
  .bubble-seg button[aria-pressed="true"], .bubble-chips button[aria-pressed="true"]{ forced-color-adjust:none; background:Highlight; color:HighlightText; }
}
.panel .hint a, .a11y-card .hint a{ color:var(--accent2); }
/* The Accessibility menu (#a11y): one scrolling panel on a sheet, so it fits any window. It is
   not scaled by fitSheets; it scrolls inside instead. */
.a11y-card{
  align-items:stretch; gap:0.7rem; text-align:start;
  width:min(28rem, calc(100vw - 1.5rem)); max-height:calc(100vh - 1.5rem); max-height:calc(100dvh - 1.5rem);
  padding:0.9rem 1rem 1rem; overflow-y:auto; overscroll-behavior:contain;
  border:1px solid var(--divider); border-radius:0.8rem; background:var(--bg-panel);
  color:var(--text); font-size:1rem;
}
.a11y-card:focus{ outline:none; }
.a11y-card:focus-visible{ outline:2px solid var(--accent2); outline-offset:-3px; }
.a11y-head{ display:flex; flex-wrap:wrap; align-items:center; justify-content:space-between; gap:0.4rem 0.6rem; }
.a11y-card .panel-row{ flex-wrap:wrap; }   /* (in the tiniest windows a label and its control stack) */
.a11y-title{ margin:0; font-size:1.3rem; font-weight:700; line-height:1.2; color:var(--accent); }
.a11y-h{ margin:0.4rem 0 -0.1rem; padding-top:0.6rem; border-top:1px solid var(--divider); font-size:0.78rem; font-weight:700; letter-spacing:0.06em; text-transform:uppercase; color:var(--text-dim); }
.a11y-card .panel-row > span, .a11y-card .panel-col > span:not(.hint){ font-size:0.9rem; }
.a11y-card .seg button{ min-height:2rem; }
.a11y-card .add-btn{ white-space:normal; }
.a11y-card .switch{ min-width:2.5rem; }

/* ---------- pinning: the shortcuts banner and the docked Accessibility panel ----------
   Pointing at the keyboard icon shows the shortcuts as a banner along the bottom edge between
   the two corner icons; pinned, it stays. The Accessibility menu, pinned, docks at the left
   instead of covering the clock. app.js (applyPins) sets data-keys-pin / data-a11y-pin on the
   page only when there is room, and --pin-b (the banner's height plus its margins, in px);
   .app then keeps that room free, so nothing pinned ever sits on the clock. */
:root{ --dock-w:clamp(16rem, 28vw, 22rem); }
.keys-bar{
  position:fixed; z-index:22;
  left:calc(max(0.4rem, env(safe-area-inset-left, 0px)) + 2.5rem); right:calc(max(0.4rem, env(safe-area-inset-right, 0px)) + 2.5rem);
  bottom:max(0.4rem, env(safe-area-inset-bottom, 0px));
  display:flex; align-items:center; gap:0.5rem; max-height:calc(100vh - 5rem); overflow-y:auto;
  padding:0.3rem 0.4rem 0.3rem 0.8rem;
  border:1px solid var(--divider); border-radius:0.7rem; background:var(--bg-panel); color:var(--text);
  font-size:0.8rem; box-shadow:0 2px 12px var(--shadow);
}
.keys-bar-list{ flex:1; min-width:0; margin:0; padding:0; list-style:none; display:flex; flex-wrap:wrap; gap:0.25rem 1rem; }
.keys-bar-list li{ white-space:nowrap; }
.keys-bar kbd{ min-width:1.5em; padding:0.05em 0.35em; font-size:0.9em; }
.pin-btn{
  flex:none; width:2rem; height:2rem; padding:0; display:flex; align-items:center; justify-content:center;
  border:1px solid var(--divider); border-radius:50%; background:none; color:var(--text-dim); cursor:pointer;
}
.pin-btn svg{ width:1.1rem; height:1.1rem; }
.pin-btn:hover{ color:var(--text); border-color:var(--text-dim); }
.pin-btn:focus-visible{ outline:2px solid var(--accent2); outline-offset:2px; }
.pin-btn[aria-pressed="true"]{ border-color:var(--accent2); color:var(--accent2); background:color-mix(in srgb, var(--accent2) 14%, var(--bg-panel)); }
.pin-btn[aria-pressed="true"] svg{ fill:currentColor; fill-opacity:0.35; }
:root[data-contrast="high"] .keys-bar, :root[data-contrast="high"] .pin-btn{ border-color:var(--text); }
:root[data-keys-pin] .app{ padding-bottom:var(--pin-b); }
.a11y-head-btns{ display:flex; align-items:center; gap:0.5rem; }
:root[data-a11y-pin] .app{
  padding-left:max(clamp(0.6rem, 2.6vw, 2rem), calc(max(0.4rem, env(safe-area-inset-left, 0px)) + var(--dock-w) + 0.6rem));
}
/* Docked: a side panel, not a dialog. It ends above the bottom row (the corner icons, or the banner). */
#a11y.docked{
  inset:auto; display:block; animation:none; background:none; z-index:20;
  left:max(0.4rem, env(safe-area-inset-left, 0px)); width:var(--dock-w);
  top:calc(env(titlebar-area-height, 0px) + 0.4rem); bottom:var(--pin-b, 2.7rem);
}
#a11y.docked .a11y-card{ width:100%; max-height:100%; }
#a11y.docked #a11y-close{ display:none; }
@media (forced-colors: active){ .pin-btn[aria-pressed="true"]{ forced-color-adjust:none; background:Highlight; color:HighlightText; border-color:Highlight; } }
