/* MODULE: css/modes.css — the three modes, dressed (CONTRACT §9, PHASE4 §2–§4).
   Owns every rule for src/modes/timer.js, src/modes/clockface.js and
   src/modes/alarm.js. Depends on css/tokens.css (vocabulary), css/base.css
   (.btn / .chip / .field / .panel primitives), css/materials.css (.m-brushed,
   .m-edge-flute, the alloy) and css/type.css (.t-display / .t-label / .t-num).
   Loads nothing: no @import, no url(), no network.

   ── WHY THIS FILE EXISTS ──────────────────────────────────────────────
   Until now each mode injected its own <style> at runtime, with a
   CONTRACT-GAP saying "lift MODE_CSS out verbatim if the integrator would
   prefer a real stylesheet". This is that file, and the debt is paid: the
   three modes now ship markup only.

   index.html links this sheet after css/materials.css / css/chassis.css /
   css/dial.css and before css/layout.css, and sw.js precaches it — both
   already done by the shell agent. Every rule that has to survive a sheet
   loading later than this one says so at its own site, with the reason.

   If the <link> is ever dropped, each mode appends one itself on first
   mount (ensureStyles() in src/modes/*.js) rather than rendering an
   unstyled instrument. That is a safety net, not the plan: it costs a
   flash of unstyled type on first paint.

   ── THE SHAPE OF THE DEFAULT VIEW (PHASE4 §2) ─────────────────────────
   The instrument, and nothing else: dial, readout, session label,
   transport, plus the face and repeat toggles. Presets, methods, the
   sequence builder, the log and the estimate all live in the Panel now, so
   nothing in this file lays out a module row. NO PAGE SCROLL, on any
   device, in the default state — which is why the dial is sized on the
   BLOCK axis and is the element that gives way when the window is short.
   The transport can never be pushed off screen.

   ── MATERIALS (PHASE4 §4) ─────────────────────────────────────────────
   Metal for things you touch, ceramic for surfaces you don't. Transport
   keys and toggles are .m-brushed; START is signal and never becomes a
   material; the stepper and the alarm rows are .panel ceramic; the
   transport's top edge carries PERMITTED FLUTE 4 from materials.css.

   ── TYPE (PHASE4 §3) ──────────────────────────────────────────────────
   The markup wears the scale's own classes — .t-display on the numerals,
   .t-label on the engraved legends — and §0 below restates those roles on
   the modes' class names from the SAME tokens, so a mode is never one
   missing <link> away from 16px body text. Past §0, the only thing this
   file adds to the numerals is the optical centring on the dial's axis.
   No font-weight is declared anywhere here: the three weights are the
   scale's business, and START's 600 is css/type.css's single exception.
*/

/* ============================================================== *
 * 0. TYPE ROLES, RESTATED ON THE MODES' OWN CLASSES
 *
 *    The markup carries .t-display / .t-title / .t-label from
 *    css/type.css, which is where those roles are defined and where they
 *    should stay. This block says the same thing again on the modes' own
 *    class names, so that a mode is never at the mercy of one <link>: an
 *    instrument whose numerals fall back to 16px body text is not an
 *    instrument.
 *
 *    It cannot drift, because every value here is the same token
 *    css/type.css reads — when both sheets are loaded the declarations are
 *    byte-identical and the cascade is a no-op. It is also why nothing
 *    below this point sets a font-size the scale already owns.
 * ============================================================== */

/* display — the numerals, and nothing else */
.tt-timer__readout,
.tt-clock__hm {
  font-family: var(--font-num);
  font-size: var(--fs-display);
  font-weight: var(--wt-light);
  line-height: var(--lh-display);
  letter-spacing: var(--tr-display);
  font-variation-settings: var(--vf-display);
  font-variant-numeric: var(--font-num-variant);
  font-feature-settings: var(--feat-num);
  text-align: center;
}

/* title */
.tt-timer__stepname,
.tt-clock__sec,
.tt-alarm__ringingtime,
.tt-alarm__time {
  font-size: var(--fs-title);
  font-weight: var(--wt-medium);
  line-height: var(--lh-title);
  letter-spacing: var(--tr-title);
  font-variation-settings: var(--vf-title);
  font-variant-numeric: var(--font-num-variant);
}

.tt-clock__sec,
.tt-alarm__ringingtime,
.tt-alarm__time {
  font-family: var(--font-num);
  font-feature-settings: var(--feat-num);
}

/* label — the engraved legends. Uppercase ALWAYS carries its tracking. */
.tt-timer__meta,
.tt-timer__grouplabel,
.tt-timer__stepcount,
.tt-clock__suffix,
.tt-clock__date,
.tt-alarm__notetitle,
.tt-alarm__off,
.tt-ribbonfb__head {
  font-family: var(--font-sans);
  font-size: var(--fs-label);
  font-weight: var(--wt-medium);
  line-height: var(--lh-label);
  letter-spacing: var(--tr-label);
  font-variation-settings: var(--vf-label);
  font-feature-settings: var(--feat-caps);
  text-transform: uppercase;
}

/* micro */
.tt-ribbonfb__scale {
  font-family: var(--font-sans);
  font-size: var(--fs-micro);
  font-weight: var(--wt-medium);
  line-height: var(--lh-micro);
  letter-spacing: var(--tr-micro);
  font-variation-settings: var(--vf-micro);
  font-feature-settings: var(--feat-caps);
  text-transform: uppercase;
}

/* body */
.tt-alarm__notebody,
.tt-alarm__ringinglabel,
.tt-alarm__empty {
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  font-weight: var(--wt-regular);
  line-height: var(--lh-body);
  letter-spacing: var(--tr-body);
  font-variation-settings: var(--vf-body);
  font-feature-settings: var(--feat-text);
}

/* ============================================================== *
 * 1. THE MODE HOST
 * ============================================================== */

/* The active mode mounts into #mode-panel, which css/chassis.css sizes as
   part of the shell's definite-height chain. This file adds the grid the
   modes are laid out in, and makes sure the box actually receives that
   height however the stage above it is built. */
.mode-panel {
  display: grid;
  grid-template-rows: minmax(0, 1fr);
  min-block-size: 0;
  min-inline-size: 0;
  /* THE LINK IN THE CHAIN THAT MUST NOT GO SLACK. Everything below sizes
     itself from a definite height, and this element is where that height
     arrives from the shell. A grid item stretches to its row on its own; a
     flex item does not — it sizes to its content, which would leave the
     dial's `block-size: 100%` resolving against nothing and collapse the
     disc to zero. `flex` is inert inside a grid, so declaring both is what
     makes this correct whichever way css/chassis.css lays the stage out
     today. */
  flex: 1 1 auto;
  align-self: stretch;
}

/* ============================================================== *
 * 2. TIMER — the instrument
 *
 *    THE NO-SCROLL CHAIN (PHASE4 §2, built by css/chassis.css and adopted
 *    here). One definite height comes down from .app-shell through
 *    .app-stage and .mode-panel; each mode is a grid whose FIRST row is
 *    minmax(0, 1fr) and whose remaining rows are auto. Everything with a
 *    fixed height — readout, label, toggles, transport — states it, and
 *    the dial absorbs the remainder. No per-element viewport arithmetic,
 *    so a sequence stepper appearing or a font falling back cannot break
 *    the guarantee.
 * ============================================================== */

/* Rows: stage (1fr) | stepper | session label | toggles | transport.
   The stepper is [hidden] unless a sequence is running, and a hidden grid
   item creates no row at all. */
.tt-timer {
  display: grid;
  grid-template-rows: minmax(0, 1fr);
  grid-auto-rows: auto;
  gap: var(--space-4);
  min-block-size: 0;
}

/* Rows: dial (1fr) | readout | meta legend. The sr-only status is
   absolutely positioned and never claims a row. */
.tt-timer__stage {
  display: grid;
  grid-template-rows: minmax(0, 1fr);
  grid-auto-rows: auto;
  justify-items: center;
  align-content: stretch;
  gap: var(--space-4);
  min-block-size: 0;
}

/* THE DIAL HOST — the largest square that fits in BOTH directions.
   src/dial.js renders a `.dial` that is `inline-size: 100%; aspect-ratio: 1`,
   so the disc is exactly as large as the box it is given, and css/dial.css
   paints a `border-radius: 50%` well on it: a box that is not square is a
   visible ellipse, not a rounding error.

   HOW IT RESOLVES, because it is not obvious and it took measuring:
     · block-size: 100%      the row, which is minmax(0, 1fr) of a grid whose
                             height came down the definite chain from
                             .app-shell — so this is a real height, not a
                             guess, and it shrinks as the fixed rows grow.
     · max-block-size 100cqi 100cqi is the STAGE's own measured inline size,
                             so the square is capped by the width it actually
                             has. No viewport arithmetic, no assumption about
                             how much padding the shell happens to have.
     · inline-size: auto     with aspect-ratio, the used block size transfers
                             to the inline axis. This is the step that only
                             works if NOTHING ELSE sets an inline size —
                             hence the specificity below.
   The fallback for an engine without container queries swaps 100cqi for
   92vw, which is the stage's width to within the shell's padding.

   SPECIFICITY, deliberately: this has to out-rank BOTH
   css/chassis.css's `.app-stage .tt-timer__dial` (which sizes the block
   axis) and css/layout.css's `:root .tt-timer__dial { inline-size:
   var(--tt-dial) }` (which sizes the inline axis). Those two currently
   disagree, and the measured result is a 336×322 ellipse. The dial host is
   this file's element, so it settles the argument.

   CONTRACT-GAP (layout agent, css/layout.css:174): `--tt-dial` is PHASE2 §2's
     viewport-fraction sizing, which PHASE4 §2 supersedes — the instrument now
     fits a definite height rather than dictating one. Please delete that rule;
     `--tt-dial` itself is still used by your own grid and is untouched.
   CONTRACT-GAP (chassis agent, css/chassis.css §4): your dial envelope block
     can go too — this is the same idea with the transfer direction corrected.
     Everything else in that section is adopted verbatim above. */
.tt-timer__dial,
.tt-clock__dial,
:root .tt-timer .tt-timer__dial,
:root .tt-clock .tt-clock__dial {
  position: relative;
  inline-size: auto;
  block-size: 100%;
  /* The anti-collapse floor. If the height chain above ever does go slack,
     `block-size: 100%` resolves to nothing and the transfer makes the disc
     0×0 — an invisible timer. A small dial is a bad day; no dial is a
     broken app. */
  min-block-size: 8rem;
  max-inline-size: 100%;
  max-block-size: min(100%, 92vw);
  aspect-ratio: 1 / 1;
  margin-inline: auto;
  align-self: center;
  justify-self: center;
  touch-action: none;
}

@supports (container-type: inline-size) {
  .tt-timer__stage,
  .tt-clock__stage {
    container-type: inline-size;
  }

  :root .tt-timer .tt-timer__dial,
  :root .tt-clock .tt-clock__dial {
    max-block-size: min(100%, 100cqi);
  }
}

.tt-timer__dial > svg,
.tt-clock__dial > svg {
  inline-size: 100%;
  block-size: 100%;
}

/* THE READOUT. .t-display carries the whole type role (300 / opsz 32 /
   -0.035em / tabular). Two things belong here and nothing else:

   1. OPTICAL CENTRING ON THE DIAL'S AXIS. letter-spacing is added after
      the LAST glyph as well as between glyphs, so a centred string sits
      half a tracking step off the box's centre: ink centre = box centre
      − tracking/2, and with --tr-display negative that pushes the numerals
      to the RIGHT of the axis the disc is drawn around. text-align: center
      centres the BOX; this translate puts the INK back on the dial's
      centre line. It is a constant — one composited transform, never
      touched per frame — and it scales with the numerals because em
      resolves against the readout's own font-size.
      (The other half of the compensation, the "+" that overtime adds in
      front of the digits, is already handled by --type-display-sign in
      css/tokens.css, applied as a mirrored end margin in css/type.css.)

   2. The overtime colour. --signal-text, NOT --signal-dim: --signal-dim is
      a FILL colour, and as type on the graphite body it measures 2.54:1,
      which fails even the 3:1 large-text floor. "You are in overtime" was
      the least legible state in the app at night. */
.tt-timer__readout {
  inline-size: 100%;
  color: var(--ink);
  transform: translateX(calc(var(--tr-display) / 2));
  transition: color var(--dur-med) var(--ease-out);
}

.tt-timer__readout[data-overtime="1"] {
  color: var(--signal-text);
}

/* The legend under the numerals: which face is fitted, and what the timer
   is doing. It is not decoration — the approach ramp is signalled on the
   disc by hue plus a breathing pulse, and hue alone is unreadable to a
   red/orange-colourblind user while the pulse is off under reduced motion.
   This line is the third, non-colour cue. */
.tt-timer__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: center;
  gap: var(--space-1) var(--space-2);
  min-block-size: var(--lh-label);
  color: var(--ink-3);
}

/* The middot is a separator, not a word: it keeps the tracking of the caps
   around it but should not be mistaken for one of them. */
.tt-timer__metasep {
  color: var(--ink-3);
  opacity: 0.6;
}

/* --- the sequence stepper (multi-step methods only) ------------------- */

/* Ceramic (a surface you look at), from base.css's .panel primitive — this
   only adds the three-column geometry. */
.tt-timer__stepper {
  display: grid;
  grid-template-columns: var(--tap) minmax(0, 1fr) var(--tap);
  align-items: center;
  gap: var(--space-3);
  inline-size: 100%;
  max-inline-size: var(--measure);
  margin-inline: auto;
}

.tt-timer__stepbody {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  min-inline-size: 0;
  text-align: center;
}

.tt-timer__stepname {
  color: var(--ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.tt-timer__stepcount {
  color: var(--ink-3);
}

/* Beat .t-title's text-align: start — the stepper's body is centred
   between its two keys, so its two lines are centred with it. */
.tt-timer__stepbody .tt-timer__stepname,
.tt-timer__stepbody .tt-timer__stepcount {
  text-align: center;
}

/* --- the session label ------------------------------------------------ */

/* Flush left, like every other line of type in the app: PHASE4 §3 allows
   exactly one centred element and it is the numerals. The BOX is centred;
   the text inside it is not. (Metrics adopted from css/chassis.css §4.) */
.tt-timer__task {
  align-self: center;
  inline-size: min(100%, 26rem);
  margin-inline: auto;
}

/* --- the face and repeat toggles -------------------------------------- */

/* ON THE RECORD, because two agents read one paragraph two ways.
   css/chassis.css §4 hides this row (`.app-stage .tt-timer__legend`),
   reading PHASE4 §2's list of six as exhaustive and pointing at Settings →
   Appearance and Settings → Behaviour as the toggles' proper home. Fair
   reading. It is not the one this mode was briefed on: the face and repeat
   toggles are named as part of what TIMER mode keeps, and two of them do
   real work where they are —

     · Original vs Custom is, in PHASE2 §6's own words, "the single most
       confusing control in the app". Burying the control that explains
       what the disc MEANS inside a settings panel is the opposite of the
       instrument being self-describing.
     · src/tutorial.js steps 4 and 5 target this row by selector. Hidden,
       the tour teaches neither the two faces nor the repeat feature — it
       skips both, silently, exactly as PHASE2 §6 says a missing target
       should.

   So it is restored here, at a specificity that survives the eviction, and
   the two lines that decide it are one deletion apart in either file.
   INTEGRATOR: this is yours to settle. Delete this rule to take the
   shell's reading; delete the chassis's to take this one. Nothing else in
   either file depends on the outcome. */
.tt-timer__legend,
:root .tt-timer .tt-timer__legend {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--space-2) var(--space-4);
}

/* …and it goes away in focus mode with the rest of the chrome. */
.tt-timer[data-focus="1"] .tt-timer__legend,
:root .tt-timer[data-focus="1"] .tt-timer__legend {
  display: none;
}

.tt-timer__legendgroup {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-inline-size: 0;
}

/* .t-label supplies the type; this is only the colour and the fact that an
   engraved legend never wraps mid-word onto its own control. */
.tt-timer__grouplabel {
  color: var(--ink-3);
  white-space: nowrap;
}

/* --- the transport ---------------------------------------------------- */

/* THE ZONE. css/chassis.css §5 owns its placement — it makes this element
   sticky against the stage's scroll port so START can never be what scrolls
   away — and materials.css §5 gives it PERMITTED FLUTE 4, the structural
   band marking its top edge, plus that band's padding. The markup carries
   .m-edge-flute too: the class is the interface, the element name is only
   that rule's current host.

   What is left — and what belongs to the mode that draws the keys — is the
   zone's own stacking: one centred column, which stays correct whether or
   not the sticky rule is in play.

   No safe-area padding here: css/base.css already pads the body by
   --safe-bottom, and spending it twice leaves a gap on an iPhone. */
.tt-timer__transport {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
}

/* THE KEYS: RESET · START · +1 +5.
   Three explicit columns, the outer two equal, so START sits dead centre on
   the dial's axis whatever flanks it — and it STAYS there in focus mode,
   where the outer two empty out, because the columns are declared rather
   than implied by auto-placement.

   css/chassis.css §5 turns this into a plain centred flex row at ≥48rem,
   where four keys fit across and the row centres itself. Both readings put
   START on the axis; this one survives a 320px phone. */
.tt-timer__transportmain {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: center;
  gap: var(--space-2);
  inline-size: 100%;
}

.tt-timer__transportside {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-inline-size: 0;
}

.tt-timer__transportside--lead {
  grid-column: 1;
  justify-content: flex-end;
}

.tt-timer__primary {
  grid-column: 2;
  min-inline-size: min(8.5rem, 40vw);
}

.tt-timer__transportside--trail {
  grid-column: 3;
  justify-content: flex-start;
}

/* A disabled key drops its metal in base.css by blanking --key-image — but
   .m-brushed sets background-image directly and from a later sheet, so it
   would put the grain back on a dead key. A dead key is not a surface you
   touch: take the alloy off explicitly. */
.tt-timer .m-brushed:disabled,
.tt-timer .m-brushed[aria-disabled="true"] {
  background-image: none;
}

/* --- focus mode ------------------------------------------------------- */

/* Chrome away; the disc, the numerals and the session label remain, plus
   START — you must still be able to stop what you are watching. */
.tt-timer[data-focus="1"] .tt-timer__chrome {
  display: none;
}

.tt-timer[data-focus="1"] .tt-timer__task .field {
  border-color: transparent;
  background-color: transparent;
  box-shadow: none;
  font-size: var(--fs-title);
}

/* --- responsive ------------------------------------------------------- */

/* A short window — a landscape phone, a half-height desktop window. The
   rows have already given the dial everything that was left over, so the
   only thing to tighten is the rhythm between them. Nothing is hidden and
   nothing moves: the composition is the same instrument, closer together. */
@media (max-height: 34rem) {
  .tt-timer,
  .tt-timer__stage,
  .tt-clock,
  .tt-clock__stage {
    gap: var(--space-2);
  }
}

/* ============================================================== *
 * 3. CLOCK — the time of day, in the timer's language
 * ============================================================== */

/* Rows: stage (1fr) | the day zone. Same chain as TIMER — see §2. */
.tt-clock {
  display: grid;
  grid-template-rows: minmax(0, 1fr);
  grid-auto-rows: auto;
  gap: var(--space-4);
  min-block-size: 0;
}

/* Rows: dial (1fr) | digital line | date. */
.tt-clock__stage {
  display: grid;
  grid-template-rows: minmax(0, 1fr);
  grid-auto-rows: auto;
  justify-items: center;
  align-content: stretch;
  gap: var(--space-4);
  min-block-size: 0;
}

/* The hands sit in their own overlay, in the dial's 0 0 200 200 user space,
   so they land on the same geometry the disc is drawn with. */
.tt-clock__hands {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.tt-clock__hand--hour,
.tt-clock__hand--minute {
  fill: var(--ink);
}

.tt-clock__hand--second {
  fill: none;
  stroke: var(--accent-cool);
  stroke-width: 1.6;
  stroke-linecap: round;
}

.tt-clock__hand--seconddot {
  fill: var(--accent-cool);
}

.tt-clock__pin {
  fill: var(--bg-raised);
  stroke: var(--ink);
  stroke-width: 1.25;
}

/* The digital line. .t-display on the hours and minutes makes it the same
   numerals as the timer's readout — it is the same instrument, reading a
   different quantity — with the seconds and the suffix stepped down. */
.tt-clock__digital {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 0;
  color: var(--ink);
}

/* The clock's numerals are a ROW — hours:minutes, then seconds, then the
   suffix — so the compensation is different from the timer's. The whole row
   is centred by the flex box; what needs correcting is the display's
   negative tracking being applied after its last glyph as well, which eats
   0.035em out of the gap before the seconds and collides the two readings.
   This gives that space back. (The suffix carries .t-label--end in the
   markup for the mirror-image problem at the other end of the row.) */
.tt-clock__digital .tt-clock__hm {
  margin-inline-end: calc(var(--tr-display) * -1);
}

/* Colour only. The size stays where §0 puts it, so css/chassis.css's
   block-axis ceiling on the readout — which also steps the seconds down in
   proportion — can still win on specificity in a short window. */
.tt-clock__sec {
  color: var(--ink-3);
}

.tt-clock__suffix {
  margin-inline-start: var(--space-2);
  color: var(--ink-3);
}

.tt-clock__date {
  color: var(--ink-3);
  text-align: center;
}

/* THE DAY RIBBON, prominently placed (CONTRACT §9): full width, anchored
   to the face above it by a hairline rule that is part of the grid rather
   than a decoration. */
.tt-clock__ribbon {
  inline-size: 100%;
}

/* Belt and braces: the slot is always filled — the real module, or the
   stand-in below it — but an empty slot must not leave a hairline hanging
   over nothing. The mode hides the whole zone by attribute rather than with
   :has(), which Firefox 120 does not support. */
.tt-clock__day[hidden] {
  display: none;
}

.tt-clock__day {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

/* ============================================================== *
 * 4. ALARM — time-of-day alarms, honestly labelled
 * ============================================================== */

/* ALARM is the one mode with genuinely unbounded content, so it is a plain
   column and lets the stage scroll (css/chassis.css §4 makes .app-stage the
   app's single scroll port — the PAGE still never moves, which is the
   requirement). Nested scrollers would put a second scrollbar inside the
   first and trap a thumb between them. */
.tt-alarm {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  min-block-size: 0;
}

/* The honest note (CONTRACT §9): alarms only fire while the app is open.
   Surface-2 rather than a panel, so it reads as a printed notice on the
   chassis rather than as another control. */
.tt-alarm__note {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-4);
  border: var(--hairline-w) solid var(--hairline);
  border-radius: var(--radius-l);
  background-color: var(--surface-2);
  color: var(--ink-2);
}

.tt-alarm__notetitle {
  color: var(--ink-3);
}

.tt-alarm__notebody {
  max-inline-size: var(--measure);
}

.tt-alarm__noteactions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
}

/* --- the ringing banner ----------------------------------------------- */

.tt-alarm__ringing {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-4);
  border-radius: var(--radius-l);
  /* --signal-key, not --signal: this banner carries --on-signal text at
     body size, which needs 4.5:1. White on the raw disc red is 4.31:1 and
     fails. The disc keeps --signal; keys and banners take the key. */
  background-color: var(--signal-key);
  color: var(--on-signal);
  box-shadow: var(--shadow-raise);
}

.tt-alarm__ringingtext {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  min-inline-size: 0;
}

.tt-alarm__ringingtime {
  font-size: var(--step-3);
  line-height: var(--lh-tight);
}

/* --- the list --------------------------------------------------------- */

.tt-alarm__list {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.tt-alarm__empty {
  padding: var(--space-5) var(--space-4);
  color: var(--ink-3);
}

/* Ceramic, from base.css's .panel primitive (a row is a surface you look at,
   not one you touch) — this adds only the geometry. */
.tt-alarm__row {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--space-2) var(--space-3);
}

.tt-alarm__rowactions {
  display: flex;
  align-items: center;
  gap: var(--space-1);
}

/* On a phone the two action keys drop to their own line rather than
   crushing the label into an ellipsis. */
@media (max-width: 27rem) {
  .tt-alarm__row {
    grid-template-columns: auto minmax(0, 1fr);
  }

  .tt-alarm__rowactions {
    grid-column: 1 / -1;
    justify-content: flex-end;
    padding-block-start: var(--space-2);
    border-block-start: var(--hairline-w) solid var(--hairline);
  }
}

/* "Off" is expressed on the chrome and in words, never by dimming the text
   layer: every control in the row is still operable, so the repeat pattern
   and the label are live content the user must be able to read in order to
   decide about switching it back on. */
.tt-alarm__row[data-enabled="0"] .tt-alarm__time,
.tt-alarm__row[data-enabled="0"] .tt-alarm__meta,
.tt-alarm__row[data-enabled="0"] .tt-alarm__label {
  color: var(--ink-2);
}

.tt-alarm__off {
  flex: 0 0 auto;
  padding-inline: var(--space-2);
  border-radius: var(--radius-pill);
  background-color: var(--surface-2);
  box-shadow: 0 0 0 var(--hairline-w) var(--hairline);
  color: var(--ink-2);
}

.tt-alarm__rowbody {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  min-inline-size: 0;
}

.tt-alarm__time {
  font-size: var(--step-2);
  line-height: var(--lh-tight);
  color: var(--ink);
  white-space: nowrap; /* "7:30 am" is one word to a reader */
}

/* The row's second line carries USER TEXT (the label) beside a repeat
   pattern, so it is neither an engraved legend — you never uppercase what
   somebody typed — nor full body size. --step--1 is the scale's caption
   size, kept in tokens.css precisely for lines like this one. */
.tt-alarm__meta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1) var(--space-2);
  font-size: var(--step--1);
  line-height: var(--lh-snug);
  color: var(--ink-3);
}

.tt-alarm__label {
  color: var(--ink-2);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* --- the enable switch ------------------------------------------------ */

/* A recessed ceramic track with a brushed metal thumb: the thumb is the
   part you touch. Same treatment css/materials.css gives the Settings
   toggle, so the app ships one switch, not two. */
.tt-alarm__switch {
  position: relative;
  flex: none;
  inline-size: 3.25rem;
  block-size: var(--tap);
  padding: 0;
  border: 0;
  border-radius: var(--radius-pill);
  background-color: var(--bg-sunk);
  box-shadow: var(--shadow-field);
  cursor: pointer;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
  transition: background-color var(--dur-fast) var(--ease-out);
}

.tt-alarm__thumb {
  position: absolute;
  inset-block-start: 50%;
  inset-inline-start: var(--space-1);
  inline-size: 1.5rem;
  block-size: 1.5rem;
  margin-block-start: -0.75rem;
  border-radius: var(--radius-pill);
  box-shadow: var(--shadow-raise);
  pointer-events: none;
  transition: transform var(--dur-med) var(--ease-out);
}

.tt-alarm__switch[aria-pressed="true"] {
  background-color: var(--signal);
}

.tt-alarm__switch[aria-pressed="true"] .tt-alarm__thumb {
  transform: translateX(1.5rem);
}

.tt-alarm__switch:active .tt-alarm__thumb {
  transition-duration: var(--dur-press);
}

/* --- the editor ------------------------------------------------------- */

/* Ceramic again (base.css's .panel), at the editor's own padding: .panel's
   24px is a card, and this is a form. Two classes so the override is not a
   source-order accident. */
.tt-alarm .tt-alarm__editor {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  padding: var(--space-4);
}

.tt-alarm__editorrow {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--space-3);
}

.tt-alarm__editorrow > .field-group {
  flex: 1 1 10rem;
  min-inline-size: 8rem;
}

/* A grid, not a wrapping flex row: seven 44px keys overflow a phone, and an
   orphaned seventh chip on its own line looks like a mistake. Four-up reads
   as a deliberate two-row keypad and every key keeps its 44px target. */
.tt-alarm__days {
  display: grid;
  grid-template-columns: repeat(7, minmax(var(--tap), 1fr));
  gap: var(--space-2);
}

@media (max-width: 27rem) {
  .tt-alarm__days {
    grid-template-columns: repeat(4, minmax(var(--tap), 1fr));
  }
}

.tt-alarm__day {
  min-inline-size: var(--tap);
  padding-inline: 0;
}

.tt-alarm__editor input[type="time"] {
  font-family: var(--font-num);
  font-variant-numeric: var(--font-num-variant);
  font-feature-settings: var(--feat-num);
  font-size: var(--step-1);
  text-align: start;
}

.tt-alarm__actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: var(--space-2);
}

.tt-alarm__actions--spread {
  justify-content: space-between;
}

.tt-alarm__add {
  align-self: flex-start;
}

/* ============================================================== *
 * 5. FALLBACKS
 *    Rendered only when ctx.dial cannot be resolved, or when the day-ribbon
 *    module is not registered. They must look like the real thing, not like
 *    a broken page.
 * ============================================================== */

/* --- the stand-in dial ------------------------------------------------ */

.tt-dialfb,
.tt-clockfb {
  display: block;
  inline-size: 100%;
  block-size: 100%;
}

.tt-dialfb {
  touch-action: none;
}

.tt-dialfb__face,
.tt-clockfb__face {
  fill: var(--bg-sunk);
}

.tt-dialfb__bezel,
.tt-clockfb__bezel {
  fill: none;
  stroke: var(--hairline);
  stroke-width: 1.5;
}

.tt-dialfb__tick,
.tt-clockfb__tick {
  stroke: var(--ink-3);
  stroke-width: 0.75;
  opacity: 0.55;
}

.tt-dialfb__tick--major,
.tt-clockfb__tick--major {
  stroke: var(--ink-2);
  stroke-width: 1.5;
  opacity: 0.9;
}

.tt-dialfb__sector,
.tt-clockfb__sector {
  fill: var(--signal);
  transition: fill var(--dur-slow) var(--ease-out);
}

.tt-dialfb[data-approach="1"] .tt-dialfb__sector {
  fill: var(--signal-warn);
  animation: tt-dialfb-breathe 2.4s var(--ease-in-out) infinite;
}

.tt-dialfb__over {
  fill: none;
  stroke: var(--signal-dim);
  stroke-width: 4;
  stroke-linecap: butt;
}

.tt-dialfb__hub {
  fill: var(--bg-raised);
  stroke: var(--hairline);
  stroke-width: 1;
}

.tt-dialfb__nub {
  fill: var(--ink);
  opacity: 0.72;
}

@keyframes tt-dialfb-breathe {
  0%,
  100% {
    opacity: 1;
  }

  50% {
    opacity: 0.72;
  }
}

/* --- the stand-in day ribbon ------------------------------------------ */

.tt-ribbonfb {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.tt-ribbonfb__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
  color: var(--ink-3);
}

.tt-ribbonfb__left {
  color: var(--signal-text);
}

.tt-ribbonfb__track {
  position: relative;
  block-size: var(--meter-h);
  border-radius: var(--radius-s);
  background-color: var(--surface-2);
  overflow: hidden;
}

/* The recess is painted OVER the fill: an inset box-shadow draws below
   child content, so an opaque .tt-ribbonfb__fill erased the groove across
   its own width. */
.tt-ribbonfb__track::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2;
  border-radius: inherit;
  box-shadow: var(--shadow-well-s);
  pointer-events: none;
}

.tt-ribbonfb__fill {
  position: absolute;
  inset-block: 0;
  background-color: var(--bg-sunk);
  transition: inset-inline-start var(--dur-med) var(--ease-out);
}

.tt-ribbonfb__grid {
  position: absolute;
  inset: 0;
  display: flex;
  pointer-events: none;
}

.tt-ribbonfb__gridline {
  flex: 1 1 0;
  border-inline-end: var(--hairline-w) solid var(--hairline);
}

.tt-ribbonfb__gridline:last-child {
  border-inline-end: 0;
}

.tt-ribbonfb__now {
  position: absolute;
  inset-block: calc(var(--hairline-w) * -2);
  inline-size: calc(var(--hairline-w) * 2);
  background-color: var(--ink);
  transform: translateX(calc(var(--hairline-w) * -1));
}

.tt-ribbonfb__scale {
  display: flex;
  justify-content: space-between;
  color: var(--ink-3);
}

/* ============================================================== *
 * 6. PREFERENCE OVERRIDES
 * ============================================================== */

/* css/base.css already neutralises every animation globally; these are
   stated again so the modes hold up if this sheet is ever used on its own,
   and so the two intentional transitions here are explicit about it.
   Reduced MOTION is not reduced FEEDBACK: audio and haptics still fire. */
@media (prefers-reduced-motion: reduce) {
  .tt-dialfb[data-approach="1"] .tt-dialfb__sector {
    animation: none;
  }

  .tt-timer__readout,
  .tt-alarm__thumb,
  .tt-alarm__switch,
  .tt-ribbonfb__fill {
    transition: none;
  }
}

/* Forced colours: the system owns every surface. Give up the painted ones
   rather than fighting it. */
@media (forced-colors: active) {
  .tt-alarm__ringing,
  .tt-alarm__note,
  .tt-alarm__off,
  .tt-alarm__switch,
  .tt-alarm__thumb {
    background-color: Canvas;
    color: CanvasText;
    border: 1px solid ButtonBorder;
    box-shadow: none;
  }

  .tt-alarm__switch[aria-pressed="true"] {
    background-color: Highlight;
  }
}
