/* ==========================================================================
   TEMPO OPERATIONS — Design System
   --------------------------------------------------------------------------
   1.  Design tokens
   2.  Base & document
   3.  Scrollbars
   4.  Focus, selection & motion
   5.  Typography
   6.  Layout & backdrop
   7.  Panels & cards
   8.  Buttons
   9.  Forms & custom selects
   10. Tabs
   11. Pills, badges & meters
   12. Tables
   13. Gantt tracks
   14. Flow gauge
   15. Modals & toast
   16. Utilities & states
   ========================================================================== */

/* ==========================================================================
   1. DESIGN TOKENS
   ========================================================================== */

/* ==========================================================================
   ARABIC FACE
   --------------------------------------------------------------------------
   One Arabic face, shipped with the app.

   This used to be an alias for whatever Calibri the viewer happened to have:
   `src: local('Calibri'), local('Carlito')`. Calibri cannot be bundled -- it is
   licensed to Microsoft -- so the app was borrowing a typeface off the machine
   and getting a different one on every machine that did not have it. Measured:
   Calibri present on the Windows desktop, Carlito present nowhere, so the phone
   in the server room and any Mac fell through to IBM Plex and rendered the same
   screen in a different face. Nobody could say what the operator was looking at.

   It also declared 400 and 600-900 and no 500, while the type scale asks for
   500 in a dozen places, so those weights were synthesised.

   Now it is the IBM Plex Sans Arabic already sitting in fonts/, at its four real
   weights, under an Arabic-only alias. The alias matters: the 'IBM Plex Sans
   Arabic' family declares Latin subsets too, so naming it directly at the head
   of a stack would take Latin away from Manrope, Playfair and DM Mono. Bound to
   the Arabic ranges alone, it claims the Arabic and leaves the rest alone.
   ========================================================================== */
@font-face {
  font-family: 'Tempo Arabic';
  src: url('fonts/ibm-plex-sans-arabic-400-arabic.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0600-06FF, U+0750-077F, U+0870-089F, U+08A0-08FF, U+FB50-FDFF, U+FE70-FEFF;
}

@font-face {
  font-family: 'Tempo Arabic';
  src: url('fonts/ibm-plex-sans-arabic-500-arabic.woff2') format('woff2');
  font-weight: 500;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0600-06FF, U+0750-077F, U+0870-089F, U+08A0-08FF, U+FB50-FDFF, U+FE70-FEFF;
}

@font-face {
  font-family: 'Tempo Arabic';
  src: url('fonts/ibm-plex-sans-arabic-600-arabic.woff2') format('woff2');
  font-weight: 600;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0600-06FF, U+0750-077F, U+0870-089F, U+08A0-08FF, U+FB50-FDFF, U+FE70-FEFF;
}

@font-face {
  font-family: 'Tempo Arabic';
  src: url('fonts/ibm-plex-sans-arabic-700-arabic.woff2') format('woff2');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0600-06FF, U+0750-077F, U+0870-089F, U+08A0-08FF, U+FB50-FDFF, U+FE70-FEFF;
}

/* Every token is in tokens.css, which index.html loads before this file and ops.css imports. Nothing here declares one. */

/* ==========================================================================
   2. BASE & DOCUMENT
   ========================================================================== */

*,
*::before,
*::after {
  box-sizing: border-box;
}

/* A <button> carries `2px outset ButtonBorder` from the user agent unless all
   four sides are declared, and that default is white here -- so any button
   class that styles its background but forgets its border draws a hard white
   box around itself. That has now caused the same visible defect three times
   (.tab-btn, then .task-card__link, .select-option and .close-btn: 23 white
   boxes on one screen), because the reset lived in each class instead of in
   one place. It lives in one place now. Widths are zeroed rather than the
   style set to `none`, so a class that wants a single edge -- .tab-btn's gold
   underline -- still gets it from `border-bottom` alone. */
/* `small` is the browser's `smaller`, 83% of whatever it sits in, which lands under 12px
   inside any small parent. It says what size it is instead. */
small { font-size: 0.75rem; }

button {
  /* A control does not inherit the page's type unless told to: it keeps the browser's
     own font (Arial, on most machines). The Display ticker, the quick actions and the
     pickers in the add form all drew in it. Said once here, so a new component cannot
     forget. */
  font: inherit;
  color: inherit;
  letter-spacing: inherit;
  border: 0 solid transparent;
  /* `buttonface` is the other half of the same problem. Under `color-scheme:
     dark` it resolves to a flat #6B6B6B, so any button class that styles its
     text but not its background wears raw browser grey -- which is what the
     quick actions and all thirteen dropdown options were doing. Verified
     against every button on the board: each of the others sets its own
     background, so clearing the default here changes only the ones that never
     chose. */
  background: transparent;
}

input,
select,
textarea {
  font: inherit;
  color: inherit;
  letter-spacing: inherit;
}

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

/* Locks the page behind an open modal so mobile doesn't scroll two layers. */
html.modal-open,
html.modal-open body {
  overflow: hidden;
}

body {
  min-height: 100vh;
  /* Clip (not hidden) — never creates a scroll container, so `position: sticky`
     table headers and fixed modals keep working. */
  overflow-x: clip;
  font-family: var(--font-sans);
  color: var(--ink);
  background-color: var(--bg);
  -webkit-font-smoothing: antialiased;
}

/* Painted as a fixed layer instead of `background-attachment: fixed`, which
   forces expensive repaints while scrolling on mobile. */
body::before {
  content: '';
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background: var(--obsidian-000);
}

img,
svg {
  max-width: 100%;
}

[x-cloak] {
  display: none !important;
}

/* ==========================================================================
   3. SCROLLBARS
   --------------------------------------------------------------------------
   The previous build hid every scrollbar globally. That removed the only
   affordance signalling that the tables, log panel, Gantt tracks and dropdown
   menus scroll at all. They are restored here, styled to match the palette.
   ========================================================================== */

* {
  scrollbar-width: thin;
  scrollbar-color: color-mix(in srgb, var(--gold-500) 38%, transparent) transparent;
}

*::-webkit-scrollbar {
  width: 10px;
  height: 10px;
}

*::-webkit-scrollbar-track {
  background: transparent;
}

*::-webkit-scrollbar-thumb {
  background: color-mix(in srgb, var(--gold-500) 32%, transparent);
  background-clip: content-box;
  border: 2px solid transparent;
  border-radius: var(--r-pill);
}

@media (hover: hover) and (pointer: fine) {
*::-webkit-scrollbar-thumb:hover {
  background: color-mix(in srgb, var(--gold-500) 58%, transparent);
  background-clip: content-box;
}
}

/* ==========================================================================
   4. FOCUS, SELECTION & MOTION
   ========================================================================== */

a:focus-visible,
button:focus-visible,
select:focus-visible,
textarea:focus-visible,
summary:focus-visible,
[role="button"]:focus-visible,
[tabindex]:focus-visible {
  /* The dashboard's ring: gold, clear of the edge, following the control's own
     corner rather than squaring it off. */
  outline: 2px solid var(--gold);
  outline-offset: 2px;
}

/* The skip link (WCAG 2.2 SC 2.4.1): off the top of the screen until a keyboard reaches it, then in the corner. The
   board's copy of ops.css .skip, so the board and the dashboard's own page show the same link. */
.skip {
  position: fixed;
  inset-block-start: 0.5rem;
  inset-inline-start: 1rem;
  z-index: 100;
  display: inline-flex;
  align-items: center;
  min-block-size: var(--control-h);
  padding-inline: 0.75rem;
  border-radius: var(--r-sm);
  background: var(--ink);
  color: var(--on-gold);
  font-size: 0.9375rem; /* a step of the type scale (15px), not the browser's 16px default */
  font-weight: 700;
  transform: translateY(-200%);
}
.skip:focus { transform: none; }

::selection {
  background: var(--gold);
  color: var(--on-gold);
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

/* ==========================================================================
   5. TYPOGRAPHY
   ========================================================================== */

.font-serif-gold {
  font-family: var(--font-serif);
}

/* Small uppercase gold kicker above a heading. Was 8–10px in several places;
   floored at 11px so it stays legible. */
.eyebrow {
  font-family: var(--font-mono);
  font-size: 0.75rem;
  font-weight: 800;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--gold-dim);
}

/* Same missing reset as .task-card__title: this is an h2 and inherits the UA
   default heading margin unless zeroed. */
.section-title {
  margin: 0;
  font-family: var(--font-serif);
  font-size: clamp(1rem, 0.94rem + 0.3vw, 1.2rem);
  font-weight: 700;
  line-height: 1.3;
  color: var(--ink-strong);
}

.text-gold-bright { color: var(--gold-100); }

.section-title--lg {
  font-size: clamp(1.15rem, 1rem + 0.6vw, 1.4rem);
}

/* Sub-section header inside the analytics panel: title on one side, count on
   the other. */
.subhead {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem 0.75rem;
  font-family: var(--font-serif);
  font-size: 0.8125rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--gold-bright);
}

.subhead__count {
  font-family: var(--font-mono);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0;
  color: var(--sage-dim);
}

/* Quranic / Hadith script */
.font-quran-script {
  font-family: var(--font-quran);
  font-size: clamp(1.15rem, 1rem + 1.1vw, 1.65rem);
  line-height: 2.2;
  letter-spacing: 0;
  word-spacing: 0;
  text-align: end;
  color: var(--gold-bright);
  font-variant-ligatures: normal;
  font-feature-settings: "kern" 1, "calt" 1, "liga" 1;
  text-rendering: optimizeLegibility;
  overflow-wrap: break-word;
}

.font-quran-script--sm {
  font-size: clamp(1rem, 0.92rem + 0.5vw, 1.2rem);
  line-height: 2;
  color: var(--alabaster-100);
}

/* Stamped gold calligraphy served as a bitmap by quran.com */
.quran-gold-calligraphy {
  display: block;
  width: auto;
  max-width: 100%;
  /* The calligraphy is the one piece of real ornament on the page; at 150px it
     was competing with the body copy instead of leading it. */
  max-height: clamp(84px, 13vw, 132px);
  margin-inline: auto;
  object-fit: contain;
  /* The bitmap is black; this turns it the deep gold of --gold-300. */
  filter: invert(33%) sepia(62%) saturate(1531%) hue-rotate(29deg) brightness(78%) contrast(105%);
}

/* ==========================================================================
   6. LAYOUT & BACKDROP
   ========================================================================== */

.app-shell {
  position: relative;
  z-index: 10;
  display: flex;
  flex-direction: column;
  gap: var(--stack);
  width: 100%;
  /* One width for every tab. It used to widen for Analytics, so the header
     and the tabs jumped sideways each time somebody switched. */
  max-width: min(90rem, 100%);
  margin-inline: auto;
  padding: 1.5rem var(--gutter) 2rem;
}

/* Watermark sigil */
.sand-sigil {
  position: fixed;
  top: 50%;
  left: 50%;
  z-index: 0;
  width: min(70vw, 480px);
  height: min(70vw, 480px);
  transform: translate(-50%, -50%);
  opacity: 0.04;
  pointer-events: none;
  color: var(--gold-500);
  /* It was blurred, glowed and blended with `screen` at 4% opacity: invisible
     detail bought with a full-viewport blend that every repaint underneath had
     to redo. On a machine without a GPU that made each frame seconds long --
     every click on the board waited on it. Flat, it looks the same. */
}

@media (max-width: 640px) {
  .sand-sigil {
    opacity: 0.03;
  }
}

/* Top bar */
.topbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1rem clamp(1rem, 3vw, 1.25rem);
}

/* The status row: who and what state (the brand, the shift's pill and clock) and, at its end, the account. It takes
   the room the actions leave, so the account stays where it always was, at the start of the buttons. */
.topbar-identity {
  display: flex;
  flex: 1 1 auto;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem 1rem;
  min-width: 0;
}
.topbar-identity > .user-chip { margin-inline-start: auto; }

.topbar-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
}

/* The shift button and Emergency are never side by side: a hand reaching for one must not land on the other.
   Together with the bar's own 0.5rem gap that is 1.5rem (24px) clear between them, the 24px WCAG 2.2 SC 2.5.8 uses
   as the spacing that makes a small target safe, here applied to two 44px ones. */
.topbar-actions > .btn-tipwrap { margin-inline-start: 1rem; }
.btn-tipwrap > .btn { flex: 1 1 auto; }

/* On a phone the header carried five buttons and stood 233px tall -- a third of the screen, before the date, before
   the tabs, before a single task. It is two rows now, and nothing in it is gone but the second "Plan tomorrow":
   planning tomorrow is the same action as the "Plan tomorrow" shortcut further down the board, and a duplicate is the
   cheapest thing to give up.
     row 1  who and what state: the brand, the shift's pill and clock, the account
     row 2  what to press: the language, the shift (Start or End), and Emergency at the far end of the row
   Each row is a fixed 44px (the height of a finger), so the bar is the same height with the clock ticking, with the
   account arriving after the page has loaded, and with the shift open or shut. */
@media (max-width: 767px) {
  .topbar {
    flex-direction: column;
    flex-wrap: nowrap;
    align-items: stretch;
    gap: 0.5rem;
    padding: 0.75rem 1rem;
  }

  .topbar-identity {
    flex: none;
    gap: 0.5rem 0.75rem;
    min-block-size: var(--control-h);
  }

  .topbar-actions {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    gap: 0.5rem;
    inline-size: 100%;
  }

  /* Scoped to the bar so it outranks `.btn`'s own display, which is declared
     later in the file and would otherwise win on source order alone. */
  .topbar-actions .topbar-action--secondary { display: none; }

  /* The second half of the wordmark is what the page title and the tab already say. */
  .brand-word small { display: none; }

  /* (Scoped to the bar: the base .brand-mark, 2.5rem, is declared after this block and would win on source order.) */
  .topbar .brand-mark {
    box-sizing: border-box;
    width: 2rem;
    height: 2rem;
  }
}

/* Under 480px the first row has the brand, the pill, the clock and the account to hold in 310px, so the wordmark's
   letters go (the mark stays) and the account is its picture (its name is the button's accessible name, and the menu
   it opens has the address). The second row has the language, the shift button and Emergency in the same 310px, with
   24px between the last two, so the language is its name alone (the other language, written in itself: WCAG 3.1.2,
   tests/visual.spec.js "Language of parts") and the buttons' side padding is a half-rem. */
@media (max-width: 479px) {
  .topbar-identity .brand-word { display: none; }
  .topbar-identity .pill { gap: 0.375rem; padding-inline: 0.5rem; }
  .topbar .user-chip__name { display: none; }
  .topbar .user-chip__button { justify-content: center; min-inline-size: var(--control-h); padding: 0.3rem; }
  .topbar-actions .btn { padding-inline: 0.5rem; }
  .topbar-actions .topbar-lang .icon { display: none; }
}

/* Under 375px the first row cannot hold the mark as well (the pill, the clock and the account take 244 of the 280px
   at 360), and the mark is decoration (it is aria-hidden); and the second row cannot hold the language's name, so it
   is its globe (its accessible name, the other language written in itself, is the button's aria-label). The bar is
   still two rows. */
@media (max-width: 374px) {
  .topbar .brand-mark { display: none; }
  .topbar-actions .topbar-lang { min-inline-size: var(--control-h); }
  .topbar-actions .topbar-lang .icon { display: inline-block; }
  .topbar-lang__label { display: none; }
}

/* Under 360px (320 is WCAG 1.4.10's reflow width, 1280 at 400%) the shift button had 49px for 57px of "Start Shift"
   and was cut to "tart Shif". Its words may take two lines inside the same 44px, rather than Emergency losing its
   name or the 24px between them. */
@media (max-width: 359px) {
  .topbar-actions .btn-tipwrap--shift > .btn, .topbar-actions > .btn--amber { white-space: normal; line-height: 1.1; text-align: center; block-size: var(--control-h); padding-block: 0; }
  /* A third of 320px is about 74px inside the card, and the shift clock "00:00:00" at 1.25rem needs about 96: the
     figures scale with the screen here (14.4px at 320), so the clock is never cut. */
  .stat-grid .stat-card__value { font-size: 4.5vw; }
}

.brand-mark {
  display: flex;
  flex: 0 0 auto;
  align-items: center;
  justify-content: center;
  width: 2.5rem;
  height: 2.5rem;
  padding: 0.5rem;
  color: var(--gold-bright);
  background: var(--panel-raised);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-sm);
}

.brand-word {
  display: flex;
  align-items: baseline;
  gap: 0.4rem;
  font-family: var(--font-mono);
  font-size: 0.8125rem;
  font-weight: 800;
  letter-spacing: 0.18em;
  color: var(--gold-bright);
}

.brand-word small {
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.18em;
  color: var(--sage-dim);
}

/* Hero
   --------------------------------------------------------------------------
   Framed rather than floating. The date and the ayah are the first thing on
   the page, and leaving them loose on the ground was what made the top of the
   app read as empty: two blocks of text with nothing holding them. The gold
   hairline and the warm gradient are the same treatment the sacred panel
   gets, because this is the same kind of content. */
/* --- the running task, within thumb's reach -------------------------------
   Phones only. It carries the two controls an operator reaches for constantly
   while the work is in hand, so that reaching them costs no scrolling at all.
   Hidden above the fold width, where the row is already on screen. */
.thumb-bar {
  position: fixed;
  inset-inline: 0;
  bottom: 0;
  z-index: 40;
  display: none;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.625rem var(--gutter);
  padding-bottom: calc(0.625rem + env(safe-area-inset-bottom, 0px));
  background: var(--panel-raised);
  border-top: 1px solid var(--gold-edge);
}

/* The bars of a person allowed more than one task at a time stack from the bottom edge; a single bar sits exactly
   where it always did. */
.thumb-stack {
  position: fixed;
  inset-inline: 0;
  bottom: 0;
  z-index: 40;
  display: none;
  flex-direction: column;
}
.thumb-stack .thumb-bar { position: static; }

.thumb-bar__what {
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
  min-width: 0;
}

.thumb-bar__title {
  overflow: hidden;
  font-size: 0.875rem;
  font-weight: 700;
  overflow-wrap: anywhere;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  color: var(--alabaster-100);
}

.thumb-bar__timer {
  font-family: var(--font-mono);
  font-size: 1.125rem;
  font-variant-numeric: tabular-nums;
  color: var(--gold-300);
}

.thumb-bar__do {
  display: flex;
  flex: 0 0 auto;
  gap: 0.5rem;
}

/* Comfortably hittable with a thumb, which the 32px icon buttons in a row are
   not once a phone is involved. */
.thumb-bar__do .icon-btn {
  width: 3rem;
  height: 3rem;
}

@media (max-width: 767px) {
  .thumb-bar { display: flex; }
  .thumb-stack { display: flex; }
  body:has(.thumb-stack > .thumb-bar + .thumb-bar) .app-shell { padding-bottom: 20rem; }
  html:has(.thumb-stack > .thumb-bar + .thumb-bar) { scroll-padding-block-end: 20rem; }
  /* So the last row of the list is never left underneath the bar -- and so a
     control scrolled into view (by a finger, by focus, by a test) stops above
     it instead of behind it. The bar holds the running task and its ticket's
     name, owner and last note, one line each. */
  body:has(.thumb-bar) .app-shell { padding-bottom: 10rem; }
  html:has(.thumb-bar) { scroll-padding-block-end: 10rem; }
  .thumb-bar .ticket-mention__name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .thumb-bar .ticket-mention__note { -webkit-line-clamp: 1; line-clamp: 1; }
}

/* --- the running task, in flow -------------------------------------------
   The desk-and-tablet counterpart to `.thumb-bar`: same content, but the row
   is already on screen so there is nothing to fix to an edge. Hidden below
   768px, where `.thumb-bar` takes over -- the two never show at once. */
.running-ribbon {
  display: none;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.875rem 1.25rem;
}

.running-ribbon__what {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.25rem 0.75rem;
  min-width: 0;
}

/* K-9: the label never wraps, and the task's name wraps instead of being cut (it showed 151px of "Internal Maintenance"). */
.running-ribbon__what .eyebrow { flex: none; white-space: nowrap; }

.running-ribbon__title {
  min-width: 0;
  font-weight: 700;
  overflow-wrap: anywhere;
  color: var(--alabaster-100);
}

.running-ribbon__timer {
  font-family: var(--font-mono);
  font-size: 1.0625rem;
  font-variant-numeric: tabular-nums;
  color: var(--gold-300);
}

.running-ribbon__do {
  display: flex;
  flex: 0 0 auto;
  gap: 0.5rem;
}

@media (min-width: 768px) {
  .running-ribbon { display: flex; }
}

/* --- start task, phone only ------------------------------------------------
   The desk already sees the whole plan; a phone gets one button in front of
   it instead, the same way it gets `.thumb-bar` instead of the ribbon.
   `.btn` sets its own `display: inline-flex` further down this file, at equal
   specificity to a single class -- the button-element qualifier here is not
   decoration, it is what keeps this rule winning the tie regardless of where
   either one happens to sit in the cascade. */
button.board-block--starttask {
  display: none;
}

@media (max-width: 767px) {
  button.board-block--starttask { display: inline-flex; }
}

/* The verse of the day, first in the document and first on the screen.
   It is given the widest gutters in the layout and the only gold edge above the
   fold, so that nothing around it competes for the eye. It used to be the
   right-hand column of the hero, level with the date. */
/* This block stays first on the page; that placement was asked for and is not
   a layout question. What it does give up is height: at its old padding it
   filled the whole first screen on a laptop, so the operator opened their own
   board and could not see a single task without scrolling. Same content, same
   position, roughly two thirds of the vertical cost. */
.ayah-banner {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  padding: clamp(1rem, 2.5vw, 1.5rem);
  background: var(--card-bg);
  border: 1px solid var(--gold-edge);
  border-radius: var(--r-lg);
}

.ayah-banner .quran-gold-calligraphy,
.ayah-banner .font-quran-script {
  align-self: center;
  text-align: center;
}

/* The English of a verse, on the board and on the Display: one typeface. DESIGN.md keeps
   serif for scripture only, and this is the scripture's own translation. */
.verse-translation {
  font-family: var(--font-serif);
  font-style: italic;
}

.ayah-banner > p:last-child {
  max-width: 68ch;
  margin-inline: auto;
  text-align: center;
}

/* On a phone the English gloss ran to six lines and was most of this block's
   height. It keeps its place and its words at a size that still reads; what it
   gives up is the leading that made it a paragraph rather than a note. */
@media (max-width: 767px) {
  .ayah-banner > p:last-child {
    font-size: 0.75rem;
    line-height: 1.5;
  }

  .quran-gold-calligraphy { max-height: 72px; }
}

/* Page furniture, not content. It used to be a full bordered card sized for
   two columns; now it is one line of text and does not need a frame around it
   to justify its place on the page. */
.hero {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0.5rem 1rem;
  padding-block: 0.25rem;
}

.hero .eyebrow { display: none; }

/* On a phone this is three lines of text wearing a full panel, and it sits
   between the operator and their task list. It keeps the words and gives up
   the chrome: no frame, no ceremony, roughly a third of the height. On a desk
   there is room for the presentation, so it stays. */
@media (max-width: 767px) {
  .hero {
    gap: 0.25rem;
    padding: 0 0.25rem;
    background: none;
    border: 0;
  }

  .hero-date {
    font-size: 1.5rem;
  }
}

.hero-date {
  font-family: var(--font-serif);
  font-size: clamp(1.25rem, 1rem + 1vw, 1.625rem);
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: -0.01em;
  color: var(--alabaster-000);
  text-wrap: balance;
}

/* Two-column dashboard: splits at 1024px, not 768px, so the tablet range
   never has to fit a 3-up stat row inside a two-thirds column. */
.tab-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-section);
}

@media (min-width: 1024px) {
  .tab-grid {
    grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
    align-items: stretch;
  }

  /* The hadith card ends where its text ends. It used to take up the difference between the two columns (a 24rem
     basis, growing), which left a short hadith in a card with a blank half; the owner chose the card the size of
     what it holds. Its text was never scrolled here (no cap beside the task list), and still is not. On a phone the
     24rem cap on .sacred-scroll stays: there a long narration would otherwise be the longest thing on the page. */
  .tab-grid > .stack > .board-block--hadith { flex: 0 0 auto; }
  .board-block--hadith .sacred-scroll { max-height: none; }

  /* K-13: beside a long task list the side column (about 1,200px at 1440, under a list of 6,000) was stretched to
     the list's height and left a screen after screen of empty column. It now keeps its own height and travels with
     the page until its end is on screen, then holds there while the list goes on: it is never cut off (top or
     bottom) and never scrolls inside itself. A column shorter than the window simply holds at the top. --side-h is
     its height, kept current by app.js. */
  .tab-grid > aside {
    align-self: start;
    position: sticky;
    top: min(var(--space-section), calc(100dvh - var(--side-h, 0px) - var(--space-section)));
  }
}

/* ---- the board on a phone ------------------------------------------------
   A desk gets two columns and can afford context around the work. A phone is
   held in a corridor or a server room, and the questions are narrower: what am
   I doing, what is next, how long has it been.

   Below 1024px the two columns collapse into one, and the source order --
   the running-task ribbon, metrics, the planned-for-today list, the add-task
   form, then the rest of the tasks, then the side column -- buried the task
   list under a full screen of preamble. Reordering here rather than in the
   markup keeps one document serving both, which is the point.

   Nothing is removed. The shortcuts, the flow gauge and the hadith are all
   still on the page, in the order somebody scrolling for them would expect. */
@media (max-width: 1023px) {
  .tab-grid { display: flex; flex-direction: column; gap: var(--space-section); }

  /* The two column wrappers stop being boxes so their children can be ordered
     against each other rather than only within their own column. */
  .tab-grid > .stack { display: contents; }

  .board-block { order: 9; }
  .board-block--views     { order: -3; }
  .board-block--owed      { order: -2; }
  .board-block--planned   { order: -1; }
  .board-block--starttask { order: 0; }
  .board-block--ribbon    { order: 1; }
  .board-block--metrics   { order: 2; }
  .board-block--add       { order: 4; }
  .board-block--tasks     { order: 5; }
  .board-block--tickets   { order: 6; }
  .board-block--focus     { order: 6; }
  .board-block--shortcuts { order: 7; }
  .board-block--hadith    { order: 8; }
}

.stack {
  display: flex;
  flex-direction: column;
  gap: var(--space-section);
  min-width: 0;
}

.stack--tight {
  gap: var(--space-tile);
}

/* Auto-fitting card rows — no breakpoint needed, and cards never drop below a
   readable width. */
/* `minmax(min(100%, 10.5rem), 1fr)` is not safe here.
 *
 * The `min()` was defensive -- never let a track be wider than its container --
 * but WebKit does not resolve a math function nested inside `minmax()` in a
 * `repeat(auto-fit, ...)` track list. It leaves the whole track list unresolved,
 * the grid computes to **zero width**, and every child collapses to 0x0. On
 * iOS Safari that silently emptied the stat cards, the manager's metric tiles
 * and every form in the app -- including the shift-plan form, so the operator
 * could not plan a day from their phone at all.
 *
 * A plain floor plus a single-column fallback says the same thing and resolves
 * everywhere. The fallback is what the `min()` was protecting against: a
 * container narrower than the track floor.
 */
.stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(10.5rem, 100%), 1fr));
  gap: 0.75rem;
}

/* Creating a task is the second thing an operator does on a phone; acting on
   the ones already there is the first. The form was 442px of the 995px sitting
   between the tabs and the first task row, so on a phone it folds behind the
   plus in its own heading and the list moves up by that much. On a desk it is
   always open -- there is no scroll worth saving there. */
.add-task-toggle {
  display: none;
  align-items: center;
  justify-content: center;
  width: 2.75rem;
  height: 2.75rem;
  border-radius: var(--r-sm);
  color: var(--gold-300);
}

.add-task-toggle svg {
  transition: transform var(--t-med) var(--ease);
}

@media (max-width: 767px) {
  .add-task-toggle { display: inline-flex; }
  /* The decorative mark gives up its place to the control. */
  .panel-head > [aria-hidden="true"] { display: none; }
  /* The add-task form specifically, by id, not every grid that happens to be
     laid out the same way.
     As a class selector this also hid the shift-plan form inside the planning
     modal, which has no disclosure and no `is-open` to give it: on a phone the
     fields were simply not there, so the operator could not plan a day from the
     device they plan days on. Nothing said so -- the modal opened, the heading
     and the buttons were present, and the middle of it was missing. */
  #add-task-form:not(.is-open) { display: none; }
}

/* Three numbers, three columns, one glance.
   auto-fit wanted 348px to place two of these and a 375px phone offers 343, so
   it fell back to one per row: 360px of stacked cards between the operator and
   their task list, for three short numbers. Asking for three explicitly costs
   each about 109px, which is more than enough for a label and a figure. */
@media (max-width: 767px) {
  .stat-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 0.5rem;
  }

  .stat-card {
    min-height: 0;
    padding: 0.625rem 0.5rem;
  }

  .stat-card__value {
    font-size: 1.25rem;
  }

  /* The encouraging line under each figure is the first thing to go when the
     column is a third of its usual width. */
  .stat-card__hint {
    display: none;
  }
}

.site-footer {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem 1.5rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--line-soft);
  font-family: var(--font-mono);
  font-size: 0.75rem;
  color: var(--sage-mute);
}

@media (max-width: 599px) {
  .site-footer {
    justify-content: center;
    text-align: center;
  }
}

/* ==========================================================================
   7. PANELS & CARDS
   ========================================================================== */

/* Border colour is driven by a custom property so variants can retint the
   panel without a specificity fight against utility classes. */
.card-panel {
  background: var(--card-bg);
  border: 1px solid var(--panel-border, var(--card-border));
  border-radius: var(--r-md);
  box-shadow: var(--shadow-tomb);
}

.card-panel--gold {
  --panel-border: color-mix(in srgb, var(--gold-500) 34%, transparent);
}

.card-panel--sage {
  --panel-border: color-mix(in srgb, var(--obsidian-500) 32%, transparent);
}

.card-panel--focus {
  background:
    linear-gradient(135deg, color-mix(in srgb, var(--gold-900) 72%, transparent), color-mix(in srgb, var(--obsidian-200) 92%, transparent)),
    var(--card-bg);
}

.card-panel--sacred {
  --panel-border: color-mix(in srgb, var(--gold-500) 34%, transparent);
  background:
    linear-gradient(135deg, color-mix(in srgb, var(--gold-900) 50%, transparent), color-mix(in srgb, var(--obsidian-200) 60%, transparent)),
    var(--card-bg);
}

.panel-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem 1rem;
  padding-bottom: 0.875rem;
  border-bottom: 1px solid var(--line);
}

.stat-card {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 0.25rem;
  min-height: 7rem;
  padding: 1rem;
}

.stat-card__label {
  font-size: 0.75rem;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--sage);
}

.stat-card__value {
  font-family: var(--font-mono);
  font-size: clamp(1.5rem, 1.2rem + 1vw, 1.875rem);
  font-weight: 700;
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
  color: var(--gold-bright);
}

.stat-card__value--muted {
  color: var(--alabaster-300);
}

.stat-card__hint {
  font-size: 0.75rem;
  color: var(--sage-dim);
}

/* Carnelian, not flame. Days missed is a reading below standard -- the warm end
   of the diverging scale -- and not an emergency. */

/* The task lists: one column or two, the reader's choice (the 1 | 2 switch
   on the plan, remembered per browser). Two only where the list itself has
   room for two 20rem cards -- narrower than that a card's controls start
   fighting its own title -- so a phone, or the day's list beside the side
   column on a small desk, falls back to one on its own. */
.task-list {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.task-list--2 {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 23rem), 1fr));
  gap: 0.5rem 1rem;
  align-items: start;
}

/* The plan: first under the tabs, across both columns. */
.planned-panel {
  grid-column: 1 / -1;
  display: flex;
  flex-direction: column;
  gap: 1rem;
  padding: 1.25rem;
}

/* A list's heading with its own controls at the far end, on one line. */
.list-head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: 0.75rem 1rem;
}

.panel-head__aside {
  display: flex;
  align-items: center;
  gap: 0.75rem;
}

.planned-panel__progress {
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--sage-dim);
}

/* An empty plan is one line in the card that already says what it is for: no second box inside the card (it used to be a
   dashed, filled rectangle with its own title, repeating the card's). */
.planned-panel__empty {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.25rem 1rem;
}

.planned-panel__empty-title { margin: 0; font-weight: 600; color: var(--ink-soft); }
.planned-panel__empty-hint { margin: 0; flex: 1 1 18rem; font-size: 0.8125rem; color: var(--sage-dim); }

/* (Every switch -- the two-column pair included -- is the one in switch.css.) */

/* The shortcuts card is for a phone, where the header has no room for "Plan tomorrow" and the tabs are a row to scroll.
   From 768px both are in the header and the tab bar: the card would say the same two things a second time. */
@media (min-width: 768px) {
  section.board-block--shortcuts { display: none; }
}

/* A row in a list, not an object floating above the page. It sits flat on the
   panel and answers the pointer with its edge and its surface -- never by
   lifting, which is what a dialog does.

   The row's surface and edge say one thing: what state this work is in. That is
   the fact that changes, and the one the board is scanned for. Where the work
   happens is said by the accent bar at the row's edge and by the badge, and is
   not repeated here. */
.task-card {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.875rem 1rem;
  border: 1px solid var(--line-soft);
  border-radius: var(--r-md);
  background-color: var(--panel);
  cursor: pointer;
  transition:
    background-color var(--t-med) var(--ease),
    border-color var(--t-med) var(--ease);
}

@media (hover: hover) and (pointer: fine) {
.task-card:hover {
  background-color: var(--panel-raised);
  border-color: var(--line);
}
}

/* The running task. One row on the board is the answer to "what am I doing",
   and it is the only row that gets the accent: a warmed surface and a gold
   edge. Nothing else on the board may take this treatment, which is what makes
   it findable without being read. */
.task-card--in_progress {
  border-color: var(--gold-edge);
  background-color: color-mix(in srgb, var(--gold-500) 7%, var(--panel));
}

@media (hover: hover) and (pointer: fine) {
.task-card--in_progress:hover {
  border-color: var(--gold-500);
  background-color: color-mix(in srgb, var(--gold-500) 10%, var(--panel));
}
}

/* Held, not broken. Warm enough to read as "this one is waiting on something",
   quiet enough that it does not compete with the row that is actually running. */
.task-card--paused {
  border-color: color-mix(in srgb, var(--carnelian-500) 38%, transparent);
  background-color: color-mix(in srgb, var(--carnelian-500) 5%, var(--panel));
}

@media (hover: hover) and (pointer: fine) {
.task-card--paused:hover {
  border-color: color-mix(in srgb, var(--carnelian-500) 62%, transparent);
}
}

/* Deliberately next, as opposed to merely present. */
.task-card--queued {
  border-color: color-mix(in srgb, var(--lapis-500) 38%, transparent);
}

@media (hover: hover) and (pointer: fine) {
.task-card--queued:hover {
  border-color: color-mix(in srgb, var(--lapis-500) 62%, transparent);
}
}

/* Pending and settled rows keep the base treatment: neutral, and quiet. */

.task-card__accent {
  flex: 0 0 auto;
  align-self: stretch;
  width: 4px;
  min-height: 2.5rem;
  border-radius: var(--r-pill);
}

.task-card__body {
  flex: 1 1 auto;
  min-width: 0;
}

/* h3 carries the UA default heading margin (~15px top and bottom) unless
   zeroed. Missed here, it added ~30px of invisible space to every task row --
   the row read as roomy in the CSS and cramped-yet-tall on screen, which is
   the opposite of what padding is supposed to buy. */
.task-card__title {
  margin: 0;
  font-size: 0.9375rem;
  font-weight: 700;
  line-height: 1.35;
  color: var(--ink-soft);
  overflow-wrap: anywhere;
}

/* The whole row is clickable for pointer users, but the keyboard entry point
   is this button — so the row never becomes a `role="button"` wrapping other
   buttons, which is invalid and unreadable to screen readers. */
.task-card__link {
  color: inherit;
  text-align: start;
  background: none;
  cursor: pointer;
}

@media (hover: hover) and (pointer: fine) {
.task-card__link:hover {
  color: var(--gold-bright);
}
}

.task-card__meta {
  display: flex;
  align-items: center;
  gap: 0.375rem;
  margin-top: 0.375rem;
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--sage-mute);
}

.task-card__controls {
  display: flex;
  flex: 0 0 auto;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: 0.5rem;
}

/* Narrow screens: the row becomes two stacked bands instead of squeezing the
   title down to one word per line. */
@media (max-width: 559px) {
  .task-card {
    flex-wrap: wrap;
  }

  .task-card__body {
    flex: 1 1 100%;
    order: 2;
  }

  .task-card__controls {
    flex: 1 1 100%;
    order: 3;
    justify-content: space-between;
    padding-top: 0.75rem;
    border-top: 1px solid var(--line-soft);
  }

  /* A marker, not a rule. Full-width it read as a divider across the card --
     and now that the card's own border carries the task's state, a second
     full-width line was the louder of the two saying the quieter thing. */
  .task-card__accent {
    width: 2.5rem;
    height: 4px;
    min-height: 0;
    order: 1;
  }
}

.quick-action {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  width: 100%;
  padding: 0.875rem 0.25rem;
  text-align: start;
  border-top: 1px solid var(--line);
  border-radius: var(--r-sm);
  transition: background var(--t-fast) var(--ease);
}

@media (hover: hover) and (pointer: fine) {
.quick-action:hover {
  background: color-mix(in srgb, var(--gold-500) 6%, transparent);
}
}

@media (hover: hover) and (pointer: fine) {
.quick-action:hover .quick-action__title {
  color: var(--gold-bright);
}
}

.quick-action__title {
  display: block;
  font-size: 0.8125rem;
  font-weight: 700;
  color: var(--alabaster-300);
  transition: color var(--t-fast);
}

.quick-action__hint {
  display: block;
  margin-top: 0.125rem;
  font-size: 0.75rem;
  color: var(--sage-dim);
}

/* Hadith text is unbounded API content — a long narration would otherwise
   stretch the sidebar past 1600px. Capped, with the overflow scrollable. */
.sacred-scroll {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  max-height: 24rem;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding-inline-end: 0.5rem;
}

.empty-state {
  padding: 1.75rem 1rem;
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--sage-dim);
  text-align: center;
  border: 1px dashed var(--line);
  border-radius: var(--r-md);
}

/* Loading has its own shape, deliberately not the empty state's. A dashed frame
   saying "nothing here" over work that is still arriving is a lie the board has
   told before. These are the rows that are coming, at the size they will be. */
.skeleton-list {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

/* One sweep, four shapes. Everything that waits uses the same material, so a
   wait reads as a wait wherever it happens rather than as four inventions. */
.skeleton-row,
.skeleton-line {
  display: block;
  background: linear-gradient(
    90deg,
    var(--panel) 0%,
    var(--panel-raised) 50%,
    var(--panel) 100%
  );
  background-size: 200% 100%;
  animation: skeleton-sweep 1.4s var(--ease) infinite;
}

/* A task row, at the height a task row actually is. */
.skeleton-row {
  height: 4.25rem;
  border: 1px solid var(--line-soft);
  border-radius: var(--r-md);
}

/* A headline figure and its label. */

/* A line of type. The width varies so a stack of them reads as text rather
   than as a barcode. */
.skeleton-line {
  height: 0.75rem;
  border-radius: var(--r-sm);
}

.skeleton-line--sm { width: 40%; }
.skeleton-line--md { width: 65%; }
.skeleton-line--lg { width: 85%; }

/* A chart, a table, a timeline: something rectangular is coming. */

.skeleton-stack {
  display: flex;
  flex-direction: column;
  gap: 0.625rem;
}

/* Staggered, so a stack reads as one thing arriving rather than several
   things pulsing in lockstep. */
.skeleton-row:nth-child(2),
.skeleton-line:nth-child(2) { animation-delay: 0.12s; }

.skeleton-row:nth-child(3),
.skeleton-line:nth-child(3) { animation-delay: 0.24s; }

@keyframes skeleton-sweep {
  from { background-position: 200% 0; }
  to   { background-position: -200% 0; }
}

/* The one looping animation in the file, and it stops the moment the thing it
   describes has finished. Reduced motion gets the shape without the sweep. */
@media (prefers-reduced-motion: reduce) {
  .skeleton-row,
  .skeleton-line { animation: none; }
}

/* Something is wrong and the operator can do something about it. Not an empty
   state, not a toast: it stays on screen and carries its own way out. */
.notice {
  display: flex;
  align-items: center;
  gap: 1rem;
  flex-wrap: wrap;
  padding: 1rem 1.125rem;
  border-radius: var(--r-md);
  border: 1px solid var(--line);
  background: var(--panel);
}

.notice__body { flex: 1 1 14rem; min-width: 0; }

.notice__title {
  display: block;
  font-size: 0.875rem;
  font-weight: 700;
  color: var(--ink-soft);
}

.notice__text {
  margin: 0.25rem 0 0;
  font-size: 0.8125rem;
  line-height: 1.5;
  color: var(--sage-dim);
}

/* Carnelian, not flame: losing the connection is a problem to be told about,
   not an emergency. Flame is reserved. */
.notice--offline {
  border-color: color-mix(in srgb, var(--carnelian-500) 45%, transparent);
  background: color-mix(in srgb, var(--carnelian-500) 6%, var(--panel));
}

/* ==========================================================================
   8. BUTTONS
   ========================================================================== */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  min-height: 2.5rem;
  padding: 0.625rem 1rem;
  font-size: 0.75rem;
  font-weight: 800;
  line-height: 1.2;
  white-space: nowrap;
  border: 1px solid transparent;
  border-radius: var(--r-sm);
  cursor: pointer;
  transition:
    background-color var(--t-fast) var(--ease),
    border-color var(--t-fast) var(--ease),
    color var(--t-fast) var(--ease),
    transform var(--t-fast) var(--ease);
}

.btn:active:not(:disabled) {
  transform: translateY(1px);
}

.btn:disabled,
.btn[disabled] {
  opacity: 0.5;
  cursor: not-allowed;
}

.btn--lg {
  min-height: 2.875rem;
  padding: 0.75rem 1.5rem;
  font-size: 0.8125rem;
}

.btn--block {
  width: 100%;
}

/* Touch pointers get a 44px minimum target. */
@media (pointer: coarse) {
  .btn {
    min-height: 2.75rem;
  }
}

.btn--gold {
  color: var(--on-gold);
  background: var(--gold);
  box-shadow: var(--shadow-1);
}

@media (hover: hover) and (pointer: fine) {
.btn--gold:hover:not(:disabled) {
  background: var(--gold-hover);
}
}

.btn--amber {
  color: var(--gold-bright);
  background: var(--gold-deep);
  border-color: var(--gold-edge);
}

@media (hover: hover) and (pointer: fine) {
.btn--amber:hover:not(:disabled) {
  color: var(--on-gold);
  background: var(--gold);
  border-color: var(--gold);
}
}

.btn--quiet {
  color: var(--alabaster-300);
  background: var(--obsidian-200);
  border-color: var(--field-edge);
}

@media (hover: hover) and (pointer: fine) {
.btn--quiet:hover:not(:disabled) {
  color: var(--ink-soft);
  background: var(--obsidian-200);
  border-color: var(--field-border-hover);
}
}

.btn--ghost {
  color: var(--sage-mute);
  background: transparent;
  font-weight: 700;
}

@media (hover: hover) and (pointer: fine) {
.btn--ghost:hover:not(:disabled) {
  color: var(--ink-soft);
  background: color-mix(in srgb, var(--alabaster-000) 5%, transparent);
}
}

/* Emergency, and the conflict a running task raises. A second red lived here
   in raw rgba -- close to flame but not equal to it, so the app had two danger
   colours and no way to change either one from the palette. */
.btn--danger {
  color: var(--flame-300);
  background: color-mix(in srgb, var(--flame-900) 85%, transparent);
  border-color: color-mix(in srgb, var(--flame-500) 45%, transparent);
}

@media (hover: hover) and (pointer: fine) {
.btn--danger:hover:not(:disabled) {
  background: var(--flame-900);
  border-color: color-mix(in srgb, var(--flame-500) 70%, transparent);
}
}

.btn--danger-solid {
  color: var(--flame-300);
  background: var(--flame-900);
  border-color: var(--flame-700);
}

@media (hover: hover) and (pointer: fine) {
.btn--danger-solid:hover:not(:disabled) {
  background: var(--flame-700);
}
}

/* Square icon-only control */
/* Every row carried a pair of these, and every one of them was gold-filled --
   so a list of eight tasks put sixteen gold objects on the page and gold
   stopped meaning "this is the thing to press". They are outlined and quiet by
   default; the running task's own controls take the accent below, because that
   row is where the next action actually is. */
.icon-btn {
  display: inline-flex;
  flex: 0 0 auto;
  align-items: center;
  justify-content: center;
  width: 2.25rem;
  height: 2.25rem;
  color: var(--alabaster-300);
  background: transparent;
  border: 1px solid var(--field-edge);
  border-radius: var(--r-sm);
  cursor: pointer;
  transition:
    background-color var(--t-fast) var(--ease),
    border-color var(--t-fast) var(--ease),
    color var(--t-fast) var(--ease),
    transform var(--t-fast) var(--ease);
}

/* The controls on the one task that is running. */
.task-card--in_progress .icon-btn {
  color: var(--gold-bright);
  background: var(--gold-deep);
  border-color: var(--gold-700);
}

@media (pointer: coarse) {
  .icon-btn {
    width: 2.75rem;
    height: 2.75rem;
  }
}

@media (hover: hover) and (pointer: fine) {
.icon-btn:hover:not(:disabled) {
  color: var(--on-gold);
  background: var(--gold);
  border-color: var(--gold);
}
}

.icon-btn:active:not(:disabled) {
  transform: translateY(1px);
}

.icon-btn:disabled,
.icon-btn[disabled] {
  opacity: 0.45;
  cursor: not-allowed;
}

@media (hover: hover) and (pointer: fine) {
.icon-btn--warn:hover:not(:disabled) {
  color: var(--on-gold);
  background: var(--carnelian-500);
}
}

/* Removing a job from the plan. Carnelian rather than flame -- it is a change
   of mind about tomorrow, not an incident -- and the action is reversible from
   the toast it raises. */
.icon-btn--danger {
  width: 1.75rem;
  height: 1.75rem;
  color: var(--carnelian-300);
  background: color-mix(in srgb, var(--carnelian-900) 70%, transparent);
  border-color: var(--carnelian-700);
}

@media (pointer: coarse) {
  .icon-btn--danger {
    width: 2.75rem;
    height: 2.75rem;
  }
}

@media (hover: hover) and (pointer: fine) {
.icon-btn--danger:hover:not(:disabled) {
  color: var(--flame-300);
  background: var(--flame-700);
}
}

/* Bare close (×) control in modal headers */
.close-btn {
  display: inline-flex;
  flex: 0 0 auto;
  align-items: center;
  justify-content: center;
  width: 2.25rem;
  height: 2.25rem;
  color: var(--alabaster-500);
  background: transparent;
  border-radius: var(--r-sm);
  cursor: pointer;
  transition: color var(--t-fast), background var(--t-fast);
}

@media (hover: hover) and (pointer: fine) {
.close-btn:hover {
  color: var(--ink-soft);
  background: color-mix(in srgb, var(--alabaster-000) 8%, transparent);
}
}

/* Every modal's way out, and the only control class in the file that never got
   a thumb-sized variant -- 36px on a phone, on the one button somebody reaches
   for while holding the device in one hand. */
@media (pointer: coarse) {
  .close-btn {
    width: 2.75rem;
    height: 2.75rem;
  }
}

/* ==========================================================================
   9. FORMS & CUSTOM SELECTS
   ========================================================================== */

.form-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(13rem, 100%), 1fr));
  gap: 1rem;
  align-items: end;
}

/* The other half of dropping `min()` from the track lists above: below this a
   container can be narrower than a track's own floor, which is the overflow the
   `min()` existed to prevent. One column, stated plainly.
   `.stat-grid` is deliberately absent — it has its own phone rule above that
   asks for three columns on purpose, and it is declared earlier, so naming it
   here would quietly overrule it. */
@media (max-width: 26rem) {
  .form-grid {
    grid-template-columns: 1fr;
  }
}

/* Spans the whole form row regardless of how many columns auto-fit produced. */
.form-grid__full {
  grid-column: 1 / -1;
}

.field {
  display: flex;
  flex-direction: column;
  gap: 0.375rem;
  min-width: 0;
}

.field-label {
  font-size: 0.75rem;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--sage);
}

.field-label--alert {
  color: var(--danger);
}

.field-hint {
  margin-top: 0.25rem;
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--sage-mute);
}

.field-input {
  width: 100%;
  min-height: 2.75rem;
  padding: 0.625rem 0.75rem;
  font-size: 0.875rem;
  font-weight: 600;
  line-height: 1.4;
  color: var(--ink-soft);
  background: var(--panel);
  border: 1px solid var(--field-border);
  border-radius: var(--r-sm);
  transition:
    border-color var(--t-fast) var(--ease),
    box-shadow var(--t-fast) var(--ease),
    background-color var(--t-fast) var(--ease);
}

.field-input::placeholder {
  font-weight: 500;
  color: var(--sage-mute);
  opacity: 1;
}

@media (hover: hover) and (pointer: fine) {
.field-input:hover:not(:disabled) {
  border-color: var(--field-border-hover);
}
}

/* Border + halo replaces the default outline so the focus ring hugs the
   control's radius. It is the only focus treatment on inputs — never removed. */
.field-input:focus,
.field-input:focus-visible {
  outline: none;
  background: var(--obsidian-050);
  border-color: var(--gold);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--gold-500) 20%, transparent);
}

/* A field still waiting for an answer. Carnelian, not flame: an unfilled box is
   something to attend to, and flame is kept for emergencies alone. */
.field-input--alert {
  border-color: color-mix(in srgb, var(--carnelian-500) 55%, transparent);
}

.field-input--alert:focus,
.field-input--alert:focus-visible {
  border-color: var(--carnelian-300);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--carnelian-500) 25%, transparent);
}

textarea.field-input {
  min-height: 6.5rem;
  line-height: 1.6;
  resize: vertical;
}

/* Native selects get the same chevron as the custom dropdown triggers. */
select.field-input {
  appearance: none;
  -webkit-appearance: none;
  padding-inline-end: 2.25rem;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%239CB3A3' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M19 9l-7 7-7-7'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.75rem center;
  background-size: 1rem;
  cursor: pointer;
}

[dir="rtl"] select.field-input {
  background-position: left 0.75rem center;
}

/* Gold-tinted native date/time picker button. */
.field-input::-webkit-calendar-picker-indicator {
  cursor: pointer;
  opacity: 0.75;
  filter: invert(33%) sepia(62%) saturate(1531%) hue-rotate(29deg) brightness(78%) contrast(105%);
}

@media (hover: hover) and (pointer: fine) {
.field-input::-webkit-calendar-picker-indicator:hover {
  opacity: 1;
}
}

/* Custom combobox */
.select-trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  width: 100%;
  min-height: 2.75rem;
  padding: 0.625rem 0.75rem;
  font-size: 0.875rem;
  font-weight: 700;
  color: var(--ink-soft);
  text-align: start;
  background: var(--panel);
  border: 1px solid var(--field-border);
  border-radius: var(--r-sm);
  cursor: pointer;
  transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
}

@media (hover: hover) and (pointer: fine) {
.select-trigger:hover {
  border-color: var(--field-border-hover);
}
}

.select-trigger[aria-expanded="true"] {
  border-color: var(--gold);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--gold-500) 20%, transparent);
}

.select-trigger__value {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.select-trigger__placeholder {
  font-weight: 600;
  color: var(--sage-mute);
}

.select-trigger__chevron {
  flex: 0 0 auto;
  width: 1rem;
  height: 1rem;
  color: var(--alabaster-500);
  transition: transform var(--t-fast) var(--ease);
}

.select-trigger[aria-expanded="true"] .select-trigger__chevron {
  transform: rotate(180deg);
}

/* Sits above sibling fields but deliberately below the modal layer (z-50). */
.select-menu {
  position: absolute;
  inset-inline: 0;
  top: calc(100% + 0.375rem);
  z-index: 40;
  max-height: 15rem;
  overflow-y: auto;
  overscroll-behavior: contain;
  background: var(--panel);
  border: 1px solid var(--gold-edge);
  border-radius: var(--r-sm);
  box-shadow: var(--shadow-2);
}

.select-option {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  width: 100%;
  padding: 0.75rem;
  font-size: 0.8125rem;
  font-weight: 700;
  color: var(--ink-soft);
  text-align: start;
  border-bottom: 1px solid var(--line-soft);
  cursor: pointer;
  transition: background var(--t-fast) var(--ease);
}

.select-option:last-child {
  border-bottom: 0;
}

@media (hover: hover) and (pointer: fine) {
.select-option:hover {
  background: var(--obsidian-200);
}
}

.select-option[aria-selected="true"] {
  color: var(--gold-bright);
  background: color-mix(in srgb, var(--gold-500) 14%, transparent);
}

/* ==========================================================================
   10. TABS
   ========================================================================== */


.tab-count {
  padding: 0.125rem 0.5rem;
  font-family: var(--font-mono);
  font-size: 0.75rem;
  font-weight: 800;
  color: var(--on-gold);
  background: var(--gold);
  border-radius: var(--r-pill);
}

/* ==========================================================================
   11. PILLS, BADGES & METERS
   ========================================================================== */

.pill {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.375rem 0.75rem;
  font-size: 0.75rem;
  font-weight: 700;
  white-space: nowrap;
  border: 1px solid;
  border-radius: var(--r-pill);
}

.pill--on {
  color: var(--gold-300);
  background: var(--gold-900);
  border-color: color-mix(in srgb, var(--gold-500) 40%, transparent);
}

.pill--off {
  color: var(--alabaster-500);
  background: var(--obsidian-200);
  border-color: var(--line);
}

.pill__dot {
  width: 0.5rem;
  height: 0.5rem;
  border-radius: var(--r-pill);
}

.pill--on .pill__dot {
  background: var(--gold-300);
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--gold-100) 15%, transparent);
}

.pill--off .pill__dot {
  background: var(--flame-500);
}

.status-badge {
  display: inline-block;
  padding: 0.1875rem 0.5rem;
  font-size: 0.75rem;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  white-space: nowrap;
  border-radius: var(--r-sm);
}

/* A timer is a reading, not a control.
   Boxed in a gold border it became the third bordered gold object on every row,
   competing with the two buttons that actually do something -- and gold is how
   this interface says "act". Stripped to what a number needs: one typeface, one
   width per digit so it cannot jitter as it counts, and a colour that sits
   behind the task title rather than in front of it. */
.timer-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  font-family: var(--font-mono);
  font-size: 0.8125rem;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.01em;
  color: var(--alabaster-300);
}

/* A count that changes width must not move what sits beside it. On a phone the
   card's controls are spread across the row, so a digit that was a pixel wider
   nudged the pause button a few pixels every second -- a moving target under a
   finger, and a tap that missed when the button moved between press and
   release. The chip reserves the width of a full reading instead. */
.task-card__controls .timer-chip {
  min-inline-size: 5.75rem;
  justify-content: flex-start;
}

/* An expectation, not a measurement, and typed as the quieter of the two. */
.timer-chip--estimate {
  font-weight: 400;
  color: var(--sage-mute);
}

/* The clock that is actually moving. This is the exception to "a reading is
   never gold": on a board built around one running task, the number counting up
   is the answer to the question the board exists to ask. */
.timer-chip--live {
  font-weight: 700;
  color: var(--gold-300);
}

/* The one timer that is worth glancing at from across the room: the shift. */
.timer-chip--shift {
  font-weight: 700;
  color: var(--gold-300);
  /* The digits of the Arabic face are not one width: a reading of all zeros is 40px wide and
     of all threes 66px. The chip sits in a header that wraps, so as the clock ticked, the row
     tipped over its wrap point and back -- the header grew and shrank by a whole line, and
     everything under it jumped 44px, several times a minute. A press that began on a button
     ended on whatever had slid under it, and was not a click. The chip holds the width of
     the widest reading, so the wrap is the same at every second. */
  min-inline-size: 4.5rem;
  justify-content: flex-start;
}

.stamp {
  padding: 0.125rem 0.5rem;
  font-family: var(--font-mono);
  font-size: 0.75rem;
  font-weight: 700;
  color: var(--gold-700);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
}

.meter {
  height: 0.5rem;
  overflow: hidden;
  background: var(--obsidian-300);
  border-radius: var(--r-pill);
}

.meter__fill {
  height: 100%;
  border-radius: var(--r-pill);
  transition: width var(--t-med) var(--ease);
}

/* ==========================================================================
   12. TABLES
   ========================================================================== */

.table-wrap {
  overflow: auto;
  /* Sideways only: a wide table must not hand a sideways swipe to the page
     (browser back), but a wheel over it has to keep scrolling the page. */
  overscroll-behavior-x: contain;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  -webkit-overflow-scrolling: touch;
}

/* Overdue work. That is a reading on the diverging scale -- behind standard --
   and the scale's warm end is carnelian. It is not an emergency. */

.data-table {
  width: 100%;
  /* Forces a horizontal scroll instead of crushing six columns into 320px. */
  min-width: 42rem;
  border-collapse: collapse;
  font-size: 0.8125rem;
  color: var(--ink-soft);
}

.data-table thead th {
  position: sticky;
  top: 0;
  z-index: 1;
  padding: 0.75rem;
  font-family: var(--font-serif);
  font-size: 0.75rem;
  font-weight: 700;
  text-align: start;
  white-space: nowrap;
  color: var(--gold-300);
  background: var(--panel-raised);
  border-bottom: 1px solid var(--line);
}

.data-table td {
  padding: 0.75rem;
  vertical-align: top;
  border-bottom: 1px solid var(--line-soft);
}

/* A row header is a <th>, and a browser centres a <th> by default -- only the
   column headings above had been told otherwise. Left as it was, the name in
   the team table sat mid-cell under a left-aligned "Person" heading. */
.data-table tbody th {
  text-align: start;
  vertical-align: top;
}

.data-table tbody tr:last-child td {
  border-bottom: 0;
}

@media (hover: hover) and (pointer: fine) {
.data-table tbody tr:hover {
  background: color-mix(in srgb, var(--obsidian-300) 75%, transparent);
}
}

.data-table--compact {
  min-width: 48rem;
  font-size: 0.75rem;
}

.data-table--compact th,
.data-table--compact td {
  padding: 0.5rem 0.625rem;
}

/* ==========================================================================
   13. GANTT TRACKS
   ========================================================================== */

/* Plan and execution share one clock axis: every bar is positioned by the time
   it happened, not merely sized by how long it took. Like every chart, it would
   read the page's way (DESIGN.md, "One reading direction"). */

/* The shift band sits behind the task bars: it is the container of the day, so
   work outside it is immediately visible as overhang. */

/* A bar with no closing log is still accruing; the pulse says the number under
   it is going to keep moving. */

/* Planned bars are drawn as outlines so a filled execution bar underneath them
   reads as the thing that actually happened. */

.btn--xs {
  padding: 0.25rem 0.5rem;
  font-size: 0.75rem;
  gap: 0.25rem;
}

/* --- planning date picker --- */

.plan-date-bar {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  flex-wrap: wrap;
  padding-bottom: 0.75rem;
  border-bottom: 1px solid var(--line-soft);
}

.plan-date-quick { display: flex; gap: 0.35rem; flex-wrap: wrap; }

.field-input--sm {
  width: auto;
  padding: 0.35rem 0.6rem;
  font-size: 0.8125rem;
}

.chip-btn {
  font-family: var(--font-mono);
  font-size: 0.75rem;
  font-weight: 600;
  padding: 0.3rem 0.55rem;
  color: var(--sage-dim);
  background: transparent;
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  cursor: pointer;
  white-space: nowrap;
  transition: color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
}

@media (hover: hover) and (pointer: fine) {
.chip-btn:hover { color: var(--ink); border-color: var(--gold); }
}

/* The plan-date quick-picks are described in the code as one-tap targets for
   planning on a phone, and were sized at roughly half a thumb. */
@media (pointer: coarse) {
  .chip-btn {
    min-height: 2.75rem;
    padding-inline: 0.9rem;
    font-size: 0.8125rem;
  }
}

.chip-btn--on {
  color: var(--on-gold);
  background: var(--gold);
  border-color: var(--gold);
}

.empty-state--sm { padding: 0.5rem 0; font-size: 0.75rem; }

/* ==========================================================================
   14. FLOW GAUGE
   ========================================================================== */

/* What needs attention, as rows rather than as a dial.
   The gauge this replaces filled 11rem of the most valuable column on the board
   to render one number that was 0% for most of every morning. These rows carry
   the work itself: what it is, where it is, and how late. */
.attention-list {
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.attention-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.5rem 0;
  border-bottom: 1px solid var(--line-soft);
}

.attention-row:last-child { border-bottom: 0; }

.attention-row__name {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
  text-align: start;
  cursor: pointer;
}

.attention-row__title {
  font-size: 0.8125rem;
  font-weight: 700;
  color: var(--ink-soft);
  overflow-wrap: anywhere;
}

@media (hover: hover) and (pointer: fine) {
.attention-row__name:hover .attention-row__title { color: var(--gold-bright); }
}

.attention-row__where {
  font-size: 0.75rem;
  color: var(--sage-mute);
}

/* How late, in the warm end of the diverging scale -- behind standard, not an
   emergency -- and always beside the words rather than instead of them. */
.attention-row__age {
  flex: 0 0 auto;
  font-family: var(--font-mono);
  font-size: 0.75rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--carnelian-300);
}

/* The same slot, saying a different kind of thing. */
.attention-row__age--estimate { color: var(--sage-mute); }

.attention-row--more {
  justify-content: flex-start;
  padding-top: 0.5rem;
  font-size: 0.75rem;
  color: var(--sage-mute);
  border-bottom: 0;
}

@media (pointer: coarse) {
  .attention-row { padding: 0.6rem 0; }
  .attention-row__name { min-height: 2.75rem; justify-content: center; }
}

/* ==========================================================================
   15. MODALS & TOAST
   ========================================================================== */

.modal-backdrop {
  position: fixed;
  inset: 0;
  z-index: 50;
  display: flex;
  padding: 1rem;
  overflow-y: auto;
  overscroll-behavior: contain;
  background: color-mix(in srgb, var(--obsidian-000) 85%, transparent);
}

/* `margin: auto` on a flex child centres it on both axes and — unlike
   `align-items: center` — never clips the top of an over-tall panel. */
.modal-panel {
  width: 100%;
  max-width: 28rem;
  margin: auto;
  padding: clamp(1.25rem, 4vw, 1.75rem);
  background: var(--card-bg);
  border: 1px solid var(--panel-border, var(--card-border));
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-tomb);
}

.modal-panel--wide {
  max-width: 34rem;
}

.modal-panel--alert {
  --panel-border: color-mix(in srgb, var(--flame-500) 50%, transparent);
}

.modal-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  padding-bottom: 0.875rem;
  margin-bottom: 1.25rem;
  border-bottom: 1px solid var(--obsidian-300);
}

/* Same missing reset, on every dialog in the app: an h2 with no margin: 0. */
.modal-title {
  margin: 0;
  font-family: var(--font-serif);
  font-size: clamp(1.1rem, 1rem + 0.5vw, 1.35rem);
  font-weight: 700;
  line-height: 1.25;
  color: var(--gold-bright);
  text-wrap: balance;
}

.modal-title--alert {
  color: var(--danger);
}

.modal-body {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.modal-section {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  padding: 1rem;
  background: var(--panel-deep);
  border: 1px solid var(--obsidian-300);
  border-radius: var(--r-sm);
}

.modal-section--gold {
  border-color: var(--gold-edge);
}

/* The one footer of every dialog: the way out first and the main action last, in reading order, so it mirrors in Arabic. */
.modal-foot {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 0.5rem;
  padding-top: 0.25rem;
}

.modal-foot .btn {
  flex: 1 1 auto;
}

@media (min-width: 480px) {
  .modal-foot .btn {
    flex: 0 0 auto;
  }
}

/* Three or more answers stand in a column, full width, in the same order. */
.modal-foot--stack {
  flex-direction: column;
  justify-content: flex-start;
}

.modal-foot--stack .btn {
  flex: 0 0 auto;
  width: 100%;
}

.modal-divider {
  padding-top: 1rem;
  border-top: 1px solid var(--obsidian-300);
}

.scroll-list {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  max-height: 12rem;
  padding-inline-end: 0.25rem;
  overflow-y: auto;
  overscroll-behavior: contain;
}

.plan-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.625rem 0.75rem;
  background: var(--panel-deep);
  border: 1px solid var(--obsidian-300);
  border-radius: var(--r-sm);
}

/* `right` was the last physical offset in the file. Under RTL -- which is the
   default here -- it pinned the toast to the side the reader's eye leaves,
   rather than the side it starts from. */
.toast {
  position: fixed;
  top: 1rem;
  inset-inline-end: 1rem;
  z-index: 100;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  max-width: calc(100vw - 2rem);
  padding: 0.75rem 1rem;
  font-size: 0.8125rem;
  font-weight: 800;
  color: var(--gold-900);
  background: var(--gold);
  border-radius: var(--r-sm);
  box-shadow: var(--shadow-2);
}

@media (min-width: 640px) {
  .toast {
    top: 1.5rem;
    inset-inline-end: 1.5rem;
    max-width: 26rem;
  }
}

/* Undo, and anything else the message can offer to put right. On gold, so it
   is drawn as an inset rather than as a second gold object. */
.toast__action {
  flex: 0 0 auto;
  margin-inline-start: 0.25rem;
  padding: 0.3rem 0.7rem;
  min-height: 2rem;
  font-size: 0.75rem;
  color: var(--gold-900);
  background: color-mix(in srgb, var(--gold-900) 16%, transparent);
  border-radius: var(--r-sm);
  cursor: pointer;
  transition: background-color var(--t-fast) var(--ease);
}

@media (hover: hover) and (pointer: fine) {
.toast__action:hover {
  background: color-mix(in srgb, var(--gold-900) 28%, transparent);
}
}

@media (pointer: coarse) {
  .toast__action { min-height: 2.75rem; padding-inline: 1rem; }
}

/* ==========================================================================
   16. UTILITIES & STATES
   ========================================================================== */

.num {
  font-variant-numeric: tabular-nums;
}

.icon {
  flex: 0 0 auto;
  width: 1rem;
  height: 1rem;
}

.icon-sm {
  flex: 0 0 auto;
  width: 0.875rem;
  height: 0.875rem;
}

/* ==========================================================================
   MEANING → MATERIAL

   Every coloured thing in the app resolves through this one block. A location,
   a status and a tone each pick a material from the palette, and the material
   supplies the text colour, the wash behind it and the edge around it as a set.
   Changing what "field" looks like is one line here, not thirty in the markup.
   ========================================================================== */

/* --- tones: what a number means ----------------------------------------- */

.tone-good    { color: var(--tone-good); }
.tone-warn    { color: var(--tone-warn); }
.tone-bad     { color: var(--tone-bad); }
.tone-info    { color: var(--tone-info); }
.tone-flat    { color: var(--tone-flat); }
.tone-accent  { color: var(--gold-300); }
.tone-muted   { color: var(--alabaster-300); }

/* Workload against the eight-hour benchmark. */
.tone-optimal { color: var(--gold-100); }

/* Distance from standard. The figure itself always stays on screen beside the
   colour, and every one of these carries a worded reading for anybody who does
   not see the difference. */

.tone-over    { color: var(--tone-info); }
.tone-under   { color: var(--tone-bad); }

.hairline-top { border-color: var(--line); }

.chip-accent {
  color: var(--gold-300);
  background: var(--gold-900);
  border: 1px solid var(--gold-edge);
}

/* --- locations ----------------------------------------------------------
   Four places, four materials: the office is gold because it is the anchor,
   the field is carnelian because it is outside, home is lapis because it is
   remote, and flame is held back for emergencies alone. */

/* The row is tinted by where the work happens, and carries the accent bar at
   its edge as well. That doubling is deliberate: the bar gives the edge a hard
   colour to catch at a glance, and the wash makes the whole row belong to a
   place when the board is scanned rather than read. The wash sits at 0.20 and
   fades out by 88%, so the badge and the timer on top of it keep their
   contrast. */
.loc {
  --loc: var(--loc-office);
}

.loc--office    { --loc: var(--loc-office); }
.loc--field     { --loc: var(--loc-field); }
.loc--home      { --loc: var(--loc-home); }
.loc--emergency { --loc: var(--loc-emergency); }

/* Finished work steps back. It is still on the board -- the day's record is the
   point -- but it is no longer one of the things asking to be picked up. It
   steps back by its ground, never by fading: faded text fails to be read. */
.loc.is-done { background: var(--panel-raised); box-shadow: none; }

.loc-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  padding: 0.1rem 0.45rem;
  font-size: 0.75rem;
  font-weight: 700;
  border-radius: var(--r-sm);
  /* Text takes the light step, the wash and the edge take the material.
     The 500s are the colour of a *place* -- right for the accent bar, which is
     a block of colour, and wrong for eleven-pixel type: home measured 3.98:1
     on the panel and emergency 3.67:1, both under the floor, in the manager's
     own tables. The 300s are the step this ramp has for type. */
  color: var(--loc-c-text, var(--loc-c));
  background: color-mix(in srgb, var(--loc-c) 14%, transparent);
  border: 1px solid color-mix(in srgb, var(--loc-c) 40%, transparent);
}

.loc-badge--office    { --loc-c: var(--loc-office);    --loc-c-text: var(--loc-office-text); }
.loc-badge--field     { --loc-c: var(--loc-field);     --loc-c-text: var(--loc-field-text); }
.loc-badge--home      { --loc-c: var(--loc-home);      --loc-c-text: var(--loc-home-text); }
.loc-badge--emergency { --loc-c: var(--loc-emergency); --loc-c-text: var(--flame-300); }

/* The rail down the edge of a task card. */
.loc-bar { background: var(--loc-c, var(--loc-office)); }
.loc-bar--office    { --loc-c: var(--loc-office); }
.loc-bar--field     { --loc-c: var(--loc-field); }
.loc-bar--home      { --loc-c: var(--loc-home); }
.loc-bar--emergency { --loc-c: var(--loc-emergency); }
.loc-bar--done      { --loc-c: var(--obsidian-400); }

/* Chart fills use the same four materials, so a bar and a badge for the same
   place are the same colour. */
.fill--office    { background: var(--loc-office);    color: var(--on-gold); }
.fill--field     { background: var(--loc-field);     color: var(--alabaster-000); }
.fill--home      { background: var(--loc-home);      color: var(--alabaster-000); }
.fill--emergency { background: var(--loc-emergency); color: var(--alabaster-000); }

.icon-loc { width: 0.875rem; height: 0.875rem; display: inline-block; stroke: currentColor; }
.icon-loc--office    { color: var(--loc-office); }
.icon-loc--field     { color: var(--loc-field); }
.icon-loc--home      { color: var(--loc-home); }
.icon-loc--emergency { color: var(--loc-emergency); }
.icon-loc--task      { color: var(--gold-500); }

/* --- status -------------------------------------------------------------
   Running work is gold — the same gold as the brand, because the running task
   is the thing the whole app exists to hold. Everything else recedes from it. */

.st {
  font-weight: 700;
  color: var(--st-c);
  background: color-mix(in srgb, var(--st-c) 13%, transparent);
  border: 1px solid color-mix(in srgb, var(--st-c) 42%, transparent);
}

.st--in_progress { --st-c: var(--status-active); }
.st--paused      { --st-c: var(--status-paused); }
.st--queued      { --st-c: var(--status-queued); }
.st--completed   { --st-c: var(--status-done); }
.st--pending     { --st-c: var(--status-pending); }
.st--cancelled   { --st-c: var(--status-cancelled); }

/* Motion is for state changes, not for ambience.
   The running badge used to pulse forever, which is decoration: it told you
   something that was already true and stayed true. Completing a task — the most
   satisfying thing that happens in this app — produced nothing at all. The
   budget moved. */

/* A card that has just settled: work finished, or called off. Plays once, when
   the class arrives, and then the card is simply quiet. */
.loc.is-done { animation: settle 520ms var(--ease) both; }

@keyframes settle {
  0%   { transform: scale(1); filter: brightness(1.25); }
  55%  { transform: scale(0.985); }
  100% { transform: scale(1); filter: brightness(1); }
}

/* The badge marks its own arrival... */
.st { animation: badge-in 260ms var(--ease) both; }

/* The running badge arrives like the others and then holds still. It used to
   keep pulsing a halo -- the fourth thing on the row saying "this is the live
   one", after its position, its timer and its own label. */
.st--in_progress {
  animation: badge-in 260ms var(--ease) both;
}

@keyframes badge-in {
  from { opacity: 0; transform: translateY(-2px); }
  to   { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .loc.is-done,
  .st,
  .st--in_progress { animation: none; }
}

/* --- workload meter ------------------------------------------------------ */

.load-badge {
  color: var(--load-c);
  background: color-mix(in srgb, var(--load-c) 15%, transparent);
  border-color: color-mix(in srgb, var(--load-c) 45%, transparent);
}
.load-badge--optimal { --load-c: var(--gold-100); }
.load-badge--over    { --load-c: var(--tone-info); }
.load-badge--under   { --load-c: var(--carnelian-300); }

.load-bar--optimal { background: var(--gold-500); }
.load-bar--over    { background: var(--lapis-500); }
.load-bar--under   { background: var(--carnelian-500); }

/* --- manager tones reuse the same four materials ------------------------- */

.status-badge--carry {
  color: var(--lapis-300);
  background: color-mix(in srgb, var(--lapis-500) 18%, transparent);
  border: 1px solid color-mix(in srgb, var(--lapis-500) 45%, transparent);
}

/* Ad hoc, filed today for today -- nothing was planned, so it gets the
   warmer of the two rather than the calm one below. */
.status-badge--new {
  color: var(--carnelian-300);
  background: color-mix(in srgb, var(--carnelian-500) 18%, transparent);
  border: 1px solid color-mix(in srgb, var(--carnelian-500) 45%, transparent);
}

/* The plan working as intended: filed on an earlier day, due today. */
.status-badge--planned {
  color: var(--faience-300);
  background: color-mix(in srgb, var(--faience-500) 18%, transparent);
  border: 1px solid color-mix(in srgb, var(--faience-500) 45%, transparent);
}

/* --- task timeline -------------------------------------------------------- */

.timeline {
  display: flex;
  flex-direction: column;
  gap: 0;
  margin: 0;
  padding: 0;
  list-style: none;
}

.timeline__item {
  display: grid;
  grid-template-columns: 0.75rem 1fr auto;
  align-items: center;
  gap: 0.75rem;
  padding: 0.5rem 0;
  border-top: 1px solid var(--line-soft);
}
.timeline__item:first-child { border-top: 0; }

/* The rail reads as one continuous strip of time: solid where the clock ran,
   hollow where it did not. */
.timeline__mark {
  position: relative;
  align-self: stretch;
  display: flex;
  justify-content: center;
}
.timeline__mark::before {
  content: "";
  width: 3px;
  border-radius: var(--r-sm);
  background: var(--gold-500);
}
.timeline__item--gap .timeline__mark::before {
  background: repeating-linear-gradient(
    180deg,
    var(--carnelian-500) 0 3px,
    transparent 3px 7px
  );
}
.timeline__item--live .timeline__mark::before {
  background: linear-gradient(180deg, var(--gold-100), var(--gold-500));
}

.timeline__body { min-width: 0; }
.timeline__label { font-size: 0.8125rem; font-weight: 700; color: var(--ink-soft); }
.timeline__meta { font-size: 0.75rem; color: var(--sage-dim); font-family: var(--font-mono); }
.timeline__value {
  font-family: var(--font-mono);
  font-size: 0.8125rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.detail-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(7rem, 100%), 1fr));
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  overflow: hidden;
}

.detail-cell {
  background: var(--panel-deep);
  padding: 0.625rem 0.75rem;
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
}

.detail-cell__label {
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--sage-mute);
}

.detail-cell__value {
  font-family: var(--font-mono);
  font-size: 0.9375rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--ink-soft);
}

/* The Analytics tab is the ops dashboard (/ops), mounted into the page in a
   shadow root (app.js, showOps). Same paper, same type, no frame: it is part
   of the page, and scrolls with it. */
.ops-embed__root {
  display: block;
  min-height: 480px;
}

/* Settings: the rules and the system's health first, then -- for a manager --
   the admin sections. */
.settings-stack {
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
}

/* ==========================================================================
   FIRST RUN

   Numbered, because this genuinely is a sequence — the clock will not run
   without a shift, and the reports say nothing without tasks. Everywhere else
   in this app numbering would be decoration; here it is the instruction.
   ========================================================================== */

.welcome {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(1.25rem, 3vw, 2rem);
  max-width: 34rem;
  margin-inline: auto;
  padding: clamp(1.75rem, 5vw, 3rem) var(--gutter);
  text-align: center;
}

.welcome__intro { display: flex; flex-direction: column; gap: 0.4rem; }

.welcome__title {
  margin: 0;
  font-family: var(--font-serif);
  font-size: clamp(1.75rem, 5vw, 2.5rem);
  font-weight: 700;
  line-height: 1.1;
  color: var(--ink);
}

.welcome__blurb {
  margin: 0;
  font-size: 0.9375rem;
  line-height: 1.65;
  color: var(--sage-dim);
  max-width: 34ch;
  margin-inline: auto;
}

.welcome__steps {
  display: flex;
  flex-direction: column;
  gap: 0;
  margin: 0;
  padding: 0;
  list-style: none;
  width: 100%;
  text-align: start;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  overflow: hidden;
  background: var(--panel-raised);
}

.welcome__step {
  display: flex;
  align-items: flex-start;
  gap: 0.9rem;
  padding: 0.9rem 1.1rem;
  border-top: 1px solid var(--line-soft);
}
.welcome__step:first-child { border-top: 0; }

.welcome__num {
  flex: 0 0 auto;
  width: 1.5rem;
  height: 1.5rem;
  display: grid;
  place-items: center;
  font-family: var(--font-mono);
  font-size: 0.75rem;
  font-weight: 700;
  color: var(--gold-300);
  border: 1px solid var(--gold-edge);
  border-radius: 50%;
}

.welcome__step strong { display: block; font-size: 0.9375rem; color: var(--ink-soft); }
.welcome__step small { display: block; font-size: 0.8125rem; color: var(--sage-mute); line-height: 1.5; margin-top: 0.1rem; }

/* ==========================================================================
   THE DOOR

   The sign-in screen is the first thing anyone sees, and for most people the
   only thing they will see if something is wrong. It gets the same care as the
   dashboard: the brand mark, one action, and a plain sentence about who is
   allowed in.
   ========================================================================== */

.gate {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: grid;
  place-items: center;
  padding: var(--gutter);
  background:
    radial-gradient(120% 80% at 50% 0%, color-mix(in srgb, var(--gold-500) 7%, transparent), transparent 60%),
    var(--bg);
}

.gate__panel {
  width: min(26rem, 100%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.875rem;
  padding: clamp(1.75rem, 5vw, 2.5rem);
  text-align: center;
  background: var(--panel);
  border: 1px solid var(--card-border);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-tomb);
}

.gate__mark {
  width: 3rem;
  height: 3rem;
  color: var(--gold-500);
}
.gate__mark svg { width: 100%; height: 100%; }

.gate__brand { margin: 0; }

.gate__title {
  font-family: var(--font-serif);
  font-size: 1.75rem;
  font-weight: 700;
  line-height: 1.1;
  margin: 0;
  color: var(--ink);
}

.gate__blurb {
  margin: 0;
  font-size: 0.875rem;
  line-height: 1.6;
  color: var(--sage-dim);
  max-width: 30ch;
}

.gate__button { width: 100%; margin-top: 0.25rem; }

.gate__note {
  margin: 0;
  font-size: 0.75rem;
  color: var(--sage-mute);
}

.gate__error {
  width: 100%;
  margin: 0;
  padding: 0.6rem 0.8rem;
  font-size: 0.8125rem;
  color: var(--flame-300);
  background: color-mix(in srgb, var(--flame-500) 14%, transparent);
  border: 1px solid color-mix(in srgb, var(--flame-500) 45%, transparent);
  border-radius: var(--r-sm);
}

.gate__lang {
  margin-top: 0.5rem;
  padding: 0.25rem 0.5rem;
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--sage-dim);
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 0.2em;
}
@media (hover: hover) and (pointer: fine) {
.gate__lang:hover { color: var(--gold-300); }
}

/* --- who is signed in ---------------------------------------------------- */

.user-chip { position: relative; }

.user-chip__button {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.3rem 0.6rem 0.3rem 0.3rem;
  background: var(--panel-deep);
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  cursor: pointer;
  color: var(--ink-soft);
  font-size: 0.75rem;
  font-weight: 700;
}
@media (hover: hover) and (pointer: fine) {
.user-chip__button:hover { border-color: var(--gold-edge); }
}
.user-chip__button:focus-visible { outline: 2px solid var(--gold-500); outline-offset: 2px; }

.user-chip__avatar {
  width: 1.5rem;
  height: 1.5rem;
  border-radius: 50%;
  object-fit: cover;
  flex: 0 0 auto;
}

.user-chip__avatar--initials {
  display: grid;
  place-items: center;
  font-size: 0.75rem;
  font-weight: 800;
  color: var(--on-gold);
  background: var(--gold-500);
}

.user-chip__name {
  max-width: 9rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.user-chip__menu {
  position: absolute;
  inset-block-start: calc(100% + 0.4rem);
  inset-inline-end: 0;
  z-index: 40;
  width: min(16rem, 80vw);
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  padding: 0.85rem;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-2);
}

.user-chip__meta {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  align-items: flex-start;
  margin: 0;
  font-size: 0.75rem;
}
.user-chip__meta small { color: var(--sage-mute); font-size: 0.75rem; letter-spacing: 0.08em; text-transform: uppercase; }
.user-chip__meta strong { color: var(--ink-soft); font-weight: 600; word-break: break-all; }

/* ==========================================================================
   THE STAGE

   A surface for the second monitor: read from two metres away, touched rarely,
   left in view all day. The rules here are the opposite of the board's — very
   few things, very large, generous air, and the one number that matters set in
   type you can read standing up.

   This is the place the display serif earns its keep. Everything is deliberate
   about being looked at rather than operated.
   ========================================================================== */

.stage {
  position: fixed;
  inset: 0;
  z-index: 50;
  display: flex;
  flex-direction: column;
  gap: clamp(1.25rem, 3vh, 2.5rem);
  padding: clamp(1.5rem, 4vw, 3.5rem);
  overflow-y: auto;
  background:
    radial-gradient(90% 60% at 50% 0%, var(--stage-wash, color-mix(in srgb, var(--gold-500) 8%, transparent)), transparent 65%),
    var(--bg);
  transition: background 900ms var(--ease);
}
/* The stage scrolls when its content is taller than the screen. Without this its sections are flex items that shrink
   to fit, and their contents then draw over each other (on a phone the buttons covered the day's figures). */
.stage > * { flex-shrink: 0; }

/* The whole room changes colour with where the work is. Glanced at from a desk
   away, the wash alone says "he is out in the field today". */
.stage--office    { --stage-wash: color-mix(in srgb, var(--faience-500) 10%, transparent); --stage-key: var(--faience-300); }
.stage--field     { --stage-wash: color-mix(in srgb, var(--carnelian-500) 11%, transparent);  --stage-key: var(--carnelian-300); }
.stage--home      { --stage-wash: color-mix(in srgb, var(--lapis-500) 11%, transparent); --stage-key: var(--lapis-300); }
.stage--emergency { --stage-wash: color-mix(in srgb, var(--flame-500) 14%, transparent);  --stage-key: var(--flame-300); }
.stage--idle      { --stage-wash: color-mix(in srgb, var(--alabaster-500) 6%, transparent); --stage-key: var(--alabaster-500); }

.stage__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  padding-bottom: clamp(0.75rem, 2vh, 1.25rem);
  border-bottom: 1px solid var(--line);
}

.stage__date {
  margin: 0;
  font-family: var(--font-serif);
  font-size: clamp(1.125rem, 2.2vw, 1.75rem);
  font-weight: 600;
  color: var(--ink-soft);
}

.stage__clock {
  margin: 0;
  font-family: var(--font-mono);
  font-size: clamp(1.125rem, 2.2vw, 1.75rem);
  font-variant-numeric: tabular-nums;
  color: var(--sage-dim);
}

/* --- what is running ------------------------------------------------------ */

.stage__now {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: clamp(0.4rem, 1.2vh, 0.9rem);
  text-align: center;
  min-height: min-content;   /* never shorter than what it holds: when the screen is short the stage scrolls (it was 0, and the buttons drew over the day's figures) */
}

.stage__eyebrow {
  margin: 0;
  font-size: clamp(0.75rem, 1vw, 0.8125rem);
  font-weight: 700;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--sage-mute);
}

.stage__task {
  margin: 0;
  font-family: var(--font-serif);
  font-weight: 700;
  font-size: clamp(2rem, 6.5vw, 5rem);
  line-height: 1.02;
  letter-spacing: -0.02em;
  text-wrap: balance;
  color: var(--ink);
  max-width: 20ch;
}

.stage__task--quiet { color: var(--alabaster-300); font-size: clamp(1.5rem, 4vw, 3rem); }

.stage__where {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0;
  font-size: clamp(0.875rem, 1.5vw, 1.125rem);
  font-weight: 600;
  color: var(--stage-key, var(--gold-300));
}
.stage__where svg { width: 1.1em; height: 1.1em; }

/* The one number the room is for. Gold, because it is the live thing — the only
   job gold has left. */
.stage__timer {
  margin: 0.25rem 0 0;
  font-family: var(--font-mono);
  font-size: clamp(3rem, 13vw, 9rem);
  font-weight: 500;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
  color: var(--gold-300);
}

.stage__timer--quiet { color: var(--alabaster-500); text-shadow: none; font-size: clamp(2rem, 7vw, 4.5rem); }

/* --- the display screen, made operable ------------------------------------
   This screen is looked at from across a room and touched with one hand while
   the other is holding something. Everything here is sized for that: controls
   you can hit without aiming, and a list you can open with a drag. */

.stage__do {
  display: flex;
  gap: 1rem;
  margin-top: 1.5rem;
}

.stage__btn {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  min-height: 3.5rem;
  padding: 0 1.5rem;
  font-family: var(--font-sans);
  font-size: 1rem;
  font-weight: 700;
  color: var(--on-gold);
  background: var(--gold-500);
  border-radius: var(--r-sm);
  cursor: pointer;
  transition: background var(--t-fast) var(--ease);
}

@media (hover: hover) and (pointer: fine) {
.stage__btn:hover { background: var(--gold-300); }
}

/* The other tasks running alongside the one in focus: a title, its timer, a pause. Absent unless a person runs several. */
.stage__also {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  width: 100%;
  max-width: 100%;
  gap: 0.5rem;
  margin: 1rem 0 0;
  padding: 0;
  list-style: none;
}
.stage__also-row {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.5rem 0.75rem;
  border: 1px solid var(--gold-edge);
  border-radius: var(--r-md);
}
.stage__also-title { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.stage__also-time { flex: 0 0 auto; font-variant-numeric: tabular-nums; color: var(--gold-300); }
.stage__also-btn {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 3rem;
  height: 3rem;
  border-radius: 50%;
  color: inherit;
  cursor: pointer;
}

/* Pausing is carnelian here as it is everywhere else -- the status badge, the
   row's edge, the pause reasons in the report. It was gold, which made the two
   actions on the display differ only in fill weight and quietly broke the one
   rule the palette is built on: one hue, one meaning. */
.stage__btn--warn {
  color: var(--carnelian-300);
  background: color-mix(in srgb, var(--carnelian-900) 80%, transparent);
  border: 1px solid var(--carnelian-700);
}

@media (hover: hover) and (pointer: fine) {
.stage__btn--warn:hover {
  color: var(--on-gold);
  background: var(--carnelian-500);
  border-color: var(--carnelian-500);
}
}

/* The day's tasks, floating at the trailing edge of the display and always
   in view. Text on the room's own colour, no panel behind it: the current
   task is lit, the rest recede, and the list fades out at both ends so it
   reads as a column that carries on rather than a box that stops. Room is
   kept for it on a wide screen; on a narrow one it drops into the flow. */
.stage__ticker {
  position: fixed;
  inset-inline-end: clamp(1rem, 2.5vw, 2.5rem);
  top: 18vh;
  bottom: 14vh;
  z-index: 30;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  width: min(22rem, 26vw);
}

.stage__ticker-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.75rem;
}

.stage__ticker-count {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  color: var(--sage-dim);
}

.stage__ticker-list {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  gap: 0.25rem;
  min-height: 0;
  padding-block: 2rem;
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: none;
  /* A mask reads only the alpha of its colours: any opaque one will do. */
  -webkit-mask-image: linear-gradient(to bottom, transparent, var(--ink) 3rem, var(--ink) calc(100% - 3rem), transparent);
  mask-image: linear-gradient(to bottom, transparent, var(--ink) 3rem, var(--ink) calc(100% - 3rem), transparent);
}

.stage__ticker-list::-webkit-scrollbar { display: none; }

.stage__ticker-list:focus-visible { outline: 2px solid var(--gold-500); outline-offset: 4px; border-radius: var(--r-md); }

@media (min-width: 1100px) {
  .stage { padding-inline-end: calc(min(22rem, 26vw) + clamp(2rem, 5vw, 5rem)); }
}

@media (max-width: 1099px) {
  .stage__ticker { position: static; width: auto; max-height: 45vh; }
}

.stage__list-empty {
  padding: 1.5rem 0;
  font-size: 0.875rem;
  color: var(--sage-dim);
}

.stage__row {
  display: flex;
  flex: 0 0 auto;
  align-items: center;
  gap: 0.75rem;
  width: 100%;
  min-height: 3.5rem;
  padding: 0.625rem 0.75rem;
  text-align: start;
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--r-md);
  cursor: pointer;
  transition: background var(--t-med) var(--ease), border-color var(--t-med) var(--ease);
}

.stage__row:focus-visible { background: color-mix(in srgb, var(--panel) 70%, transparent); }
@media (hover: hover) and (pointer: fine) {
.stage__row:hover:not(:disabled) { background: color-mix(in srgb, var(--panel) 70%, transparent); }
}

/* The rest step back by ink, not by fading -- faded text is text that fails
   its contrast floor. */
.stage__row:not(.is-current):not(.is-running) .stage__row-title { color: var(--sage-dim); }

.stage__row.is-current {
  background: var(--panel);
  border-color: var(--line);
  box-shadow: var(--shadow-1);
}

.stage__row.is-running {
  border-color: var(--gold-edge);
  cursor: default;
}

.stage__row-bar {
  flex: 0 0 auto;
  align-self: stretch;
  width: 3px;
  border-radius: var(--r-pill);
}

.stage__row-what {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  gap: 0.125rem;
  min-width: 0;
}

.stage__row-title {
  overflow: hidden;
  font-size: 0.9375rem;
  font-weight: 700;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--alabaster-100);
}

.stage__row-where {
  font-size: 0.75rem;
  color: var(--sage-mute);
}

.stage__row-urgent {
  flex: 0 0 auto;
  padding: 0.125rem 0.4rem;
  font-size: 0.75rem;
  font-weight: 700;
  color: var(--flame-300);
  background: var(--flame-900);
  border-radius: var(--r-sm);
}

.stage__row-late {
  flex: 0 0 auto;
  padding: 0.125rem 0.4rem;
  font-size: 0.75rem;
  font-weight: 700;
  color: var(--carnelian-300);
  background: var(--carnelian-900);
  border-radius: var(--r-sm);
}

.stage__row-time.is-estimate { font-weight: 400; color: var(--sage-mute); }

.stage__row-time {
  flex: 0 0 auto;
  font-family: var(--font-mono);
  font-size: 0.8125rem;
  font-variant-numeric: tabular-nums;
  color: var(--alabaster-300);
}

@media (prefers-reduced-motion: reduce) {
  .stage__row { transition: none; }
}

.stage__note {
  margin: 0;
  max-width: 44ch;
  font-size: clamp(0.8125rem, 1.3vw, 1rem);
  line-height: 1.6;
  color: var(--sage-dim);
}

/* --- how the day is going -------------------------------------------------- */

.stage__day {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(7rem, 100%), 1fr));
  gap: clamp(0.75rem, 2vw, 2rem);
  padding-top: clamp(0.75rem, 2vh, 1.25rem);
  border-top: 1px solid var(--line);
}

.stage__stat { display: flex; flex-direction: column; gap: 0.15rem; align-items: center; text-align: center; }

.stage__stat-value {
  font-family: var(--font-mono);
  font-size: clamp(1.25rem, 2.6vw, 2rem);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--ink-soft);
}

.stage__stat-label {
  font-size: clamp(0.75rem, 0.9vw, 0.8125rem);
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--sage-mute);
}

.stage__meter {
  height: 3px;
  border-radius: var(--r-sm);
  background: color-mix(in srgb, var(--alabaster-500) 16%, transparent);
  overflow: hidden;
}

.stage__meter-fill {
  display: block;
  height: 100%;
  background: linear-gradient(90deg, var(--gold-700), var(--gold-300));
  transition: width 900ms var(--ease);
}

/* --- the verse -------------------------------------------------------------- */

.stage__verse {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5rem;
  text-align: center;
  padding-top: clamp(0.5rem, 1.5vh, 1rem);
}

.stage__calligraphy {
  max-width: min(46rem, 92%);
  max-height: 18vh;
  object-fit: contain;
  filter: invert(33%) sepia(62%) saturate(1531%) hue-rotate(29deg) brightness(78%) contrast(105%);
  opacity: 0.9;
}

.stage__ayah-en {
  margin: 0;
  max-width: 52ch;
  font-size: clamp(0.8125rem, 1.3vw, 1rem);
  line-height: 1.7;
  color: var(--sage-dim);
}

.stage__surah {
  margin: 0;
  font-family: var(--font-mono);
  font-size: 0.75rem;
  letter-spacing: 0.14em;
  color: var(--sage-mute);
}

/* --- the way out ------------------------------------------------------------ */

.stage__exit {
  position: absolute;
  inset-block-start: clamp(1rem, 3vw, 2rem);
  inset-inline-start: clamp(1rem, 3vw, 2rem);
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.4rem 0.7rem;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--sage-mute);
  background: transparent;
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  cursor: pointer;
  /* Present but not competing: the point of this screen is everything else.
     Quiet by colour and a faint edge, never by fading -- a control too faint
     to read is one nobody can find. */
  border-color: var(--line-soft);
  transition: color var(--t-med) var(--ease), border-color var(--t-med) var(--ease);
}

@media (hover: hover) and (pointer: fine) {
.stage:hover .stage__exit { border-color: var(--line); }
}
@media (hover: hover) and (pointer: fine) {
.stage__exit:hover { color: var(--ink); border-color: var(--gold-edge); }
}
.stage__exit:focus-visible { outline: 2px solid var(--gold-500); outline-offset: 2px; }

@media (prefers-reduced-motion: reduce) {
  .stage, .stage__meter-fill { transition: none; }
}

/* The Exit chip and the date share the top corner at every width: the room above the head is the chip's own (its offset
   plus its height), so the date and the clock sit under it, not behind it. It was reserved below 1100 px only, and on a
   desk the chip covered the date (QA F-1). */
.stage { padding-block-start: calc(clamp(1rem, 3vw, 2rem) + 3rem); }

/* ==========================================================================
   ONE DESIGN LANGUAGE
   ==========================================================================
   The board, analytics, settings and the display are one app, so they are
   drawn one way -- the ops dashboard's, which is the clearest of the three
   the app used to speak. The whole of it, in one paragraph:

     A surface is a white card on paper: a hairline edge, a 14px corner, a
     soft shadow. Everything inside a card -- buttons, fields, rows, tables,
     sub-panels -- has the 9px corner. Headings are the sans at 700 in ink;
     labels are small grey capitals; figures are the mono. Text comes in
     three inks (ink, a softer ink for secondary lines, grey for labels and
     hints), all at least 4.5:1. Colour is spent on meaning -- status, place,
     attention, the one gold "act" -- never on decoration.

   This section restates every component in those terms and comes last, so
   it is the one that holds. Serif type is kept for scripture only.
   ========================================================================== */

/* ---- surfaces ------------------------------------------------------------ */
.card-panel,
.card-panel--gold,
.card-panel--sage,
.card-panel--focus,
.card-panel--sacred,
.ayah-banner,
.modal-panel {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-1);
}

.modal-panel { box-shadow: var(--shadow-tomb); }

/* A card that says something gets a coloured top edge, the dashboard's way
   of saying it: what is left (gold), what is done (faience), time (lapis),
   what is overdue (carnelian). */
.stat-card { border-top: 4px solid var(--line); }
.stat-grid > .stat-card:nth-child(1) { border-top-color: var(--gold-500); }
.stat-grid > .stat-card:nth-child(2) { border-top-color: var(--faience-500); }
.stat-grid > .stat-card:nth-child(3) { border-top-color: var(--lapis-500); }
.card-panel--focus { border-top: 4px solid var(--carnelian-500); }
/* Scripture is set apart by its type, not by a different card: the verse
   banner and the hadith are the same white card as everything else. */
.ayah-banner { padding: 1.25rem; }

/* ---- type ---------------------------------------------------------------- */
.hero-date,
.section-title,
.subhead,
.modal-title,
.welcome__title,
.gate__title,
.stage__date,
.stage__task,
.font-serif-gold,
.tab-btn,
.data-table thead th {
  font-family: var(--font-sans);
}

.hero-date { font-weight: 800; letter-spacing: -0.01em; color: var(--ink); }
.section-title { font-size: 1rem; font-weight: 700; color: var(--ink); }
.section-title--lg { font-size: 1.25rem; }
.subhead { font-size: 0.9375rem; font-weight: 700; color: var(--ink); }
.modal-title { font-size: 1.125rem; font-weight: 700; color: var(--ink); }
.stage__task { font-weight: 800; letter-spacing: -0.02em; }

/* Labels: small grey capitals, one style everywhere. */
.eyebrow,
.stage__eyebrow,
.stat-card__label,
.field-label {
  font-family: var(--font-sans);
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--sage-dim);
}

.field-label--alert { color: var(--flame-300); }

/* Figures: the mono, in ink. Meaning is on the card's edge, not the digits. */
.stat-card__value {
  font-family: var(--font-mono);
  font-weight: 700;
  color: var(--ink);
}

.stat-card__value--muted { color: var(--sage); }
.stat-card__hint { color: var(--sage-dim); }

/* Hints and stamps are quiet facts, not decoration. */
.stamp {
  font-family: var(--font-sans);
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--sage-dim);
  background: var(--panel-raised);
  border-color: var(--line);
  border-radius: var(--r-pill);
}

/* ---- navigation: the two main tabs are the one switch (switch.css), and Display is a button beside it ------------
   The tabs are a tray sized by their labels, at the start of the row; Display is a mode that leaves the page, not a
   tab, so it is an ordinary button at the other end, outside the tablist. On a phone the tabs are equal columns across
   the row, icon over label, so all of them are on screen and none needs a sideways scroll to be found (a long label
   wraps to a second line rather than being clipped, and the count rides the corner of the icon), and Display is an
   icon at the end of the row. */
.tabs {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-tile);
}

.tab-btn { white-space: nowrap; }

.tabs .tabs__display { min-block-size: var(--control-h); }

.tab-count {
  color: var(--gold-300);
  background: var(--gold-900);
}

@media (max-width: 639px) {
  /* The tabs filled the tray to its edge, so the selected one's pill sat 4px from the tray's rim and the labels
     touched it (the design detector's "cramped padding"). A quarter-rem of tray around the buttons gives the pill room
     to sit in; each button is still at least 44px (it is the icon over a label, taller than that). */
  .tabs__list { flex: 1 1 0; min-inline-size: 0; grid-auto-columns: minmax(0, 1fr); padding: 0.25rem; }
  /* The label stays for a screen reader (and the tooltip); the icon is what is seen. */
  .tabs .tabs__display { inline-size: var(--control-h); padding: 0; align-self: stretch; }
  .tabs__display > span { position: absolute; inline-size: 1px; block-size: 1px; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; }
}

@media (max-width: 479px) {
  .tabs__list .tab-btn {
    position: relative;
    flex-direction: column;
    justify-content: flex-start;
    gap: 0.25rem;
    min-inline-size: 0;
    padding-inline: 0.25rem;
    white-space: normal;
    text-wrap: balance;
  }

  .tab-count {
    position: absolute;
    inset-block-start: 0.25rem;
    inset-inline-end: 0.25rem;
    padding: 0.0625rem 0.375rem;
  }
}

/* ---- buttons ---------------------------------------------------------------- */
.btn {
  min-height: var(--control-h);
  padding: 0.5rem 0.875rem;
  font-family: var(--font-sans);
  font-size: 0.8125rem;
  font-weight: 600;
  letter-spacing: 0;
  text-transform: none;
  border-radius: var(--r-md);
}

.btn--lg { min-height: var(--control-h); padding: 0.625rem 1.25rem; font-size: 0.875rem; }
.btn--xs { min-height: 1.75rem; padding: 0.25rem 0.625rem; font-size: 0.75rem; }

.btn--quiet {
  color: var(--ink);
  background: var(--panel);
  border-color: var(--field-edge);
}

@media (hover: hover) and (pointer: fine) {
.btn--quiet:hover:not(:disabled) {
  color: var(--ink);
  background: var(--panel);
  border-color: var(--sage-mute);
}
}

.btn--gold { box-shadow: none; }

.icon-btn {
  color: var(--ink-soft);
  background: var(--panel);
  border-color: var(--field-edge);
  border-radius: var(--r-md);
}

/* ---- fields ------------------------------------------------------------------ */
.field-input,
.select-trigger {
  min-height: var(--control-h);
  padding: 0.4375rem 0.75rem;
  font-weight: 500;
  color: var(--ink);
  background: var(--panel);
  border-color: var(--field-edge);
  border-radius: var(--r-md);
}

@media (hover: hover) and (pointer: fine) {
.field-input:hover,
.select-trigger:hover { border-color: var(--sage-mute); }
}

.select-menu {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-2);
}

/* A finger needs more than a pointer: 44px on a touch screen. */
@media (pointer: coarse) {
  .btn, .field-input, .select-trigger { min-height: 2.75rem; }
  .icon-btn { width: 2.75rem; height: 2.75rem; }
}

/* ---- chips and statuses: the dashboard's pills --------------------------------- */
.status-badge {
  padding: 0.0625rem 0.5rem;
  font-family: var(--font-sans);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0;
  text-transform: none;
  border-radius: var(--r-pill);
}

.st {
  background: color-mix(in srgb, var(--st-c) 10%, var(--panel));
  border-color: color-mix(in srgb, var(--st-c) 35%, var(--panel));
}

.pill {
  font-size: 0.75rem;
  font-weight: 800;
  letter-spacing: 0.06em;
}

/* ---- tables: the register's --------------------------------------------------- */
.table-wrap {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
}

.data-table thead th {
  padding: 0.625rem 0.75rem;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  text-align: start;
  color: var(--sage-dim);
  background: var(--panel-raised);
  border-bottom: 1px solid var(--line);
}

.data-table tbody td,
.data-table tbody th {
  padding: 0.5625rem 0.75rem;
  color: var(--ink-soft);
  border-bottom: 1px solid var(--line);
  vertical-align: middle;
}

.data-table tbody tr:last-child > * { border-bottom: 0; }
@media (hover: hover) and (pointer: fine) {
.data-table tbody tr:hover > * { background: var(--panel-raised); }
}

/* ---- rows and cards inside cards -------------------------------------------------- */
.task-card {
  border-color: var(--line);
  border-radius: var(--r-md);
}

@media (hover: hover) and (pointer: fine) {
.task-card:hover { border-color: var(--obsidian-400); box-shadow: var(--shadow-1); }
}

.modal-section,
.modal-section--gold {
  border-radius: var(--r-md);
}

/* ---- the admin sections in Settings: a card each, like the rules above them ------ */
.settings-admin > .card-panel { background: transparent; border: 0; box-shadow: none; padding: 0; }
.settings-admin .modal-section {
  padding: 1.125rem 1.25rem;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-1);
}
.text-gold-bright { color: var(--ink); }

/* ---- headings: one line, the dashboard's way -------------------------------
   A card is titled once. The small label that used to sit above each title
   ("THE PLAN" over "Planned for today") said the same thing twice, and the
   rule under it drew a line the dashboard's cards do not have. */
.panel-head { padding-bottom: 0; border-bottom: 0; }
.panel-head .eyebrow:has(+ .section-title),
.list-head .eyebrow:has(+ .section-title),
.eyebrow:has(+ .section-title) { display: none; }

/* Row actions sit in a flex box inside the cell; the cell itself stays a
   table cell, so the row keeps one height and one rule under it. */
.row-actions { display: flex; flex-wrap: wrap; gap: 0.375rem; }

/* An edited row that has not been saved says so, in the colour that means act. */
.row-unsaved { display: block; margin-block-start: 0.25rem; color: var(--gold-300); font-size: 0.75rem; font-weight: 600; }

/* Arabic letters join; spacing them out, as the Latin wordmark is, breaks them apart. */
:lang(ar) .brand-word, .brand-word:lang(ar), :lang(ar) .brand-word small, .brand-word small:lang(ar) { letter-spacing: 0; text-transform: none; }

/* ==========================================================================
   THE DASHBOARD, ALL THE WAY IN
   ==========================================================================
   The section above set the app's cards, type and tables in the dashboard's
   terms. These are the places it had not reached: every dialog, every table
   inside Settings, every field when it has focus, and the small furniture --
   the close button, the empty state, the section heading inside a card.
   Each rule names the dashboard part it copies (ops.css), so the two can be
   read side by side.
   ========================================================================== */

/* ---- dialogs: the dashboard's drawer ------------------------------------------
   ops.css .scrim / .drawer. A dim ink scrim behind, not a paper haze: the page
   underneath is still there, just not the thing to read. The dialog itself is
   paper with a white head across its top, and what it holds sits on that paper
   as white sections -- the drawer's .drawer__head, .drawer__body and .dsec. */
.modal-backdrop {
  background: color-mix(in srgb, var(--ink) 28%, transparent);
}

.modal-panel,
.modal-panel--wide,
.modal-panel--alert {
  padding: 0;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-tomb);
}

/* An alarm keeps its edge where the drawer keeps its tone: along the start. */
.modal-panel--alert { border-inline-start: 6px solid var(--flame-500); }

.modal-head {
  align-items: center;
  margin: 0;
  padding: 1rem 1.375rem 0.875rem;
  background: var(--panel);
  border-bottom: 1px solid var(--line);
  border-radius: var(--r-lg) var(--r-lg) 0 0;
}

/* ops.css .drawer__kicker over .drawer__title. */
.modal-head .eyebrow { display: block; margin: 0 0 0.125rem; }
.modal-head .eyebrow:has(+ .modal-title) { display: block; }
.modal-title {
  font-family: var(--font-sans);
  font-size: 1.3125rem;
  font-weight: 800;
  line-height: 1.2;
  color: var(--ink);
}
.modal-title--alert { color: var(--danger); }

.modal-body {
  gap: 1rem;
  padding: 1.125rem 1.375rem 1.375rem;
}

/* The emergency form's running clock: from the press of the button to now. Its width is reserved for the widest reading, so the
   line does not move as the digits change. */
.modal-timer {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.5rem;
  margin: 0;
  font-size: 0.875rem;
  color: var(--sage-dim);
}
.modal-timer .num {
  min-inline-size: 8ch;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--danger);
}

/* ops.css .dsec: a white section with a small grey capital heading. */
.modal-section,
.modal-section--gold {
  gap: 0.625rem;
  padding: 0.875rem 1rem;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
}
.modal-section--gold { border-color: var(--gold-edge); }

.modal-section > .subhead,
.modal-section > h3 {
  font-family: var(--font-sans);
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--sage-dim);
}

.modal-divider { border-top-color: var(--line); }

/* ops.css .drawer__close: a round button with a hairline, not a bare glyph. */
.close-btn {
  width: 2.125rem;
  height: 2.125rem;
  color: var(--ink-soft);
  background: var(--panel);
  border: 1px solid var(--field-edge);
  border-radius: 50%;
}
@media (hover: hover) and (pointer: fine) {
.close-btn:hover { color: var(--ink); background: var(--bg); }
}
.close-btn:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }

/* The two dialogs that are a record to read rather than a question to answer
   -- a task's details and the plan for a day -- open the way the dashboard's
   details do: a panel along the inline end, full height, sliding in. */
.modal-backdrop--drawer { padding: 0; overflow: hidden; }
.modal-backdrop--drawer > .modal-panel {
  width: min(620px, 100vw);
  max-width: none;
  height: 100%;
  margin: 0;
  margin-inline-start: auto;
  overflow-y: auto;
  overscroll-behavior: contain;
  border: 0;
  border-inline-start: 6px solid var(--obsidian-500);
  border-radius: 0;
  animation: drawer-in 180ms var(--ease) both;
}
.modal-backdrop--drawer .modal-head {
  position: sticky;
  top: 0;
  z-index: 2;
  border-radius: 0;
}
@keyframes drawer-in { from { transform: translateX(30px); opacity: 0.4; } }
[dir="rtl"] .modal-backdrop--drawer > .modal-panel { animation-name: drawer-in-rtl; }
@keyframes drawer-in-rtl { from { transform: translateX(-30px); opacity: 0.4; } }
@media (prefers-reduced-motion: reduce) {
  .modal-backdrop--drawer > .modal-panel { animation: none; }
}
/* The sign-off's footer stays in reach at the foot of a long drawer, as its head stays at the top. */
.modal-foot--sticky {
  position: sticky;
  bottom: 0;
  z-index: 2;
  padding-block: 0.75rem;
  background: var(--panel);
  border-top: 1px solid var(--line);
}
.modal-foot__note { flex: 1 1 100%; margin: 0; }

/* ---- figures in a dialog: the drawer's stat tiles ------------------------------
   ops.css .dstats / .dstat: separate white tiles, the figure large in the mono
   and its name small underneath, instead of one grey grid of cells. */
.detail-grid {
  gap: 0.5rem;
  grid-template-columns: repeat(auto-fill, minmax(min(8.25rem, 100%), 1fr));
  background: transparent;
  border: 0;
  border-radius: 0;
  overflow: visible;
}
.detail-cell {
  flex-direction: column-reverse;
  justify-content: flex-end;
  gap: 0.125rem;
  padding: 0.625rem 0.75rem;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
}
.detail-cell__label {
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0;
  text-transform: none;
  color: var(--sage-dim);
}
.detail-cell__value {
  font-size: 1.0625rem;
  line-height: 1.25;
  white-space: nowrap;
  color: var(--ink);
}

/* ---- fields: focus is an outline, as on the dashboard -------------------------
   ops.css :focus-visible. A focused field used to change colour, gain a glow and
   tint its own background; on the dashboard it keeps its face and gets the gold
   ring, the same ring every other control in the app gets. */
.field-input:focus,
.field-input:focus-visible,
.select-trigger[aria-expanded="true"] {
  background: var(--panel);
  border-color: var(--field-edge);
  box-shadow: none;
  outline: 2px solid var(--gold);
  outline-offset: 1px;
}
.field-input--alert:focus,
.field-input--alert:focus-visible { outline-color: var(--carnelian-300); box-shadow: none; }

/* ---- chips: words in the sans --------------------------------------------------
   ops.css .chip. The mono is for figures; a chip that says "Tomorrow" is a word. */
.chip-btn {
  font-family: var(--font-sans);
  font-size: 0.75rem;
  color: var(--ink-soft);
  background: var(--panel);
  border-color: var(--field-edge);
}
@media (hover: hover) and (pointer: fine) {
.chip-btn:hover { border-color: var(--sage-mute); }
}
.chip-btn--on { color: var(--on-gold); background: var(--gold); border-color: var(--gold); }

/* ---- empty states: ops.css .empty -- a quiet line, not a dashed box ------------ */
.empty-state {
  padding: 0.75rem 0;
  text-align: start;
  border: 0;
  border-radius: 0;
}

/* ---- Settings' admin sections: the dashboard's blocks --------------------------
   ops.css .block with its h2 and .block__note. On the dashboard a block is
   titled in plain words at 16px; the admin sections were titled in small gold
   capitals, which on the dashboard is how a section *inside* a drawer is named. */
.settings-admin .modal-section { gap: 0.875rem; padding: 1.125rem 1.25rem; }
.settings-admin .modal-section > .subhead {
  font-size: 1rem;
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink);
}
.settings-admin .modal-section > .subhead + p { margin: -0.5rem 0 0; font-size: 0.75rem; color: var(--sage-dim); }

/* ---- tables: the register, cell for cell ---------------------------------------
   ops.css .register. Body text in ink at 14px, a field inside a cell at the
   dashboard's control height, and the wrap clipped to its own corner. */
.table-wrap { overflow: auto; }
.data-table { font-size: 0.875rem; }
.data-table tbody td,
.data-table tbody th { color: var(--ink); }
.data-table .field-input,
.data-table .select-trigger {
  min-height: 2.25rem;
  padding-block: 0.3125rem;
  font-size: 0.8125rem;
}
.data-table small,
.data-table .text-xs { color: var(--sage-dim); }
@media (pointer: coarse) {
  .data-table .field-input, .data-table .select-trigger { min-height: 2.75rem; }
}

/* The add row sits on one line, the way the dashboard's controls bar does:
   the fields, then the button that acts on them, at the end of the same row
   rather than alone under it. */
@media (min-width: 40rem) {
  .settings-admin .form-grid { grid-template-columns: repeat(2, minmax(0, 18rem)) auto; justify-content: start; }
  .settings-admin .form-grid > .form-grid__full { grid-column: auto; }
}

/* ---- the masthead: the verse, and the date and clock beside it -------------
   One row above the toolbar. The verse has no frame of its own now -- it is
   set apart by its calligraphy, not by a card -- and the date and clock sit at
   the row's far end behind a hairline, the dashboard's way of dividing two
   things on one line. On a phone the two stack, the verse still first. */
.masthead {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: 1rem 2rem;
}
.masthead .ayah-banner {
  padding: 0;
  background: none;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  /* The verse arrives after the page does, from a service that may take
     seconds. It used to push the whole board down 50-120px whenever it landed
     -- under a finger, or under a click that had already begun. The banner now
     holds the room it will need (the image, and at most four lines of text),
     so its arrival moves nothing. */
  min-block-size: 15rem;
}
.masthead .ayah-banner > p {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 4;
  line-clamp: 4;
  overflow: hidden;
}
.masthead .hero {
  align-self: stretch;
  align-items: center;
  padding-block: 0;
  padding-inline-start: 2rem;
  border-inline-start: 1px solid var(--line);
}
.masthead .hero > div { align-items: flex-end; text-align: end; }
.masthead .hero-date,
.hero-clock { margin: 0; }
.masthead .hero > div { gap: 0.25rem; }
.hero-clock {
  font-family: var(--font-mono);
  font-size: 1.125rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--sage);
}
@media (max-width: 767px) {
  .masthead { grid-template-columns: 1fr; gap: 0.75rem; }
  .masthead .hero { padding-inline-start: 0; border-inline-start: 0; }
  .masthead .hero > div { align-items: flex-start; text-align: start; }
}

/* ---- the verse on a phone: one line until it is opened ----------------------
   The banner held room for the whole verse (15rem: picture, four lines of translation) on a screen that has 844px.
   Closed, it is what the verse is at a glance: the heading row (the surah, "Another", and the button that opens it),
   the picture at 2.5rem, and one line of the translation. "Full verse" opens it to the picture at its old size and the
   whole translation. The heading row's "Renews daily" is a note, not a control, and is shown with the whole verse.
   The closed banner reserves exactly the height of those three rows, so the verse arriving from its service moves
   nothing (tests/tickets-ui.spec.js, "Nothing moves when the verse arrives"). From 768px up none of this applies:
   the button is not drawn and the banner is the whole verse, as before. */
.ayah-banner .verse-toggle { display: none; }
@media (max-width: 767px) {
  .ayah-banner .verse-toggle { display: inline-flex; }
  .masthead .ayah-banner { gap: 0.5rem; }
  .masthead .ayah-banner > p { margin-block: 0; }
  .masthead .ayah-banner:not(.is-open) {
    min-block-size: calc(var(--control-h) + 2.5rem + 1.3125rem + 2 * 0.5rem);
  }
  .masthead .ayah-banner:not(.is-open) .stamp { display: none; }
  .masthead .ayah-banner:not(.is-open) .quran-gold-calligraphy {
    block-size: 2.5rem;
    max-height: none;
  }
  .masthead .ayah-banner:not(.is-open) > p {
    -webkit-line-clamp: 1;
    line-clamp: 1;
    line-height: 1.5;
  }
  .masthead .ayah-banner.is-open { min-block-size: 0; }
  .masthead .ayah-banner.is-open > p {
    display: block;
    -webkit-line-clamp: unset;
    line-clamp: unset;
    overflow: visible;
  }
}

/* ---- Tickets -------------------------------------------------------------
   One card per ticket. The card's own surface and edge say what state the work
   is in and nothing else does: gold for a ticket with a task actually running,
   carnelian for one held on somebody outside IT, a step back in opacity for
   settled ones. The status is also written as a word, because colour is never
   the only carrier. Where the work happens is a task's fact, and is said by
   the task, not repeated here. */
.ticket-list { display: flex; flex-direction: column; gap: 0.75rem; }

.ticket-card {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.875rem 1rem;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background-color: var(--panel);
  cursor: pointer;
  transition: background-color var(--t-med) var(--ease), border-color var(--t-med) var(--ease);
}
@media (hover: hover) and (pointer: fine) {
.ticket-card:hover { background-color: var(--panel-raised); }
}
.ticket-card--running {
  border-color: var(--gold-edge);
  background-color: color-mix(in srgb, var(--gold-500) 7%, var(--panel));
}
.ticket-card--waiting {
  border-color: color-mix(in srgb, var(--carnelian-500) 38%, transparent);
  background-color: color-mix(in srgb, var(--carnelian-500) 5%, var(--panel));
}
.ticket-card--settled { opacity: 0.78; }

.ticket-card__sub { margin: 0; font-size: 0.75rem; font-weight: 700; color: var(--sage); }
.ticket-tasks, .ticket-notes { display: flex; flex-direction: column; gap: 0.5rem; margin: 0; padding: 0; list-style: none; }
.ticket-notes { font-size: 0.8125rem; color: var(--ink); }
.ticket-task {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  align-items: center;
  gap: 0.25rem 0.75rem;
  padding: 0.5rem 0.625rem;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
}
.ticket-task__name { font-size: 0.8125rem; font-weight: 600; color: var(--ink); overflow-wrap: anywhere; }
.ticket-task__state { font-size: 0.75rem; font-weight: 600; color: var(--sage); }
.ticket-task__time { font-family: var(--font-mono); font-size: 0.75rem; font-variant-numeric: tabular-nums; color: var(--alabaster-300); }
.ticket-task__dates { grid-column: 1 / -1; font-size: 0.75rem; color: var(--sage-mute); overflow-wrap: anywhere; }
.ticket-task__dates:empty { display: none; }
.ticket-task__controls { display: flex; gap: 0.375rem; grid-column: 1 / -1; }
.ticket-task__controls:empty { display: none; }
.ticket-task__notes { grid-column: 1 / -1; }
.ticket-card__actions { display: flex; flex-wrap: wrap; gap: 0.5rem; }

.notice--owed {
  border-color: var(--gold-edge);
  background: color-mix(in srgb, var(--gold-500) 6%, var(--panel));
}

/* The note sheet. Not a dialog: no backdrop, no trap, and it sits in the
   corner rather than across the page, so a pending question never covers the
   controls the operator is in the middle of using. */
.note-sheet {
  position: fixed;
  inset-inline: 0.75rem;
  inset-block-end: 0.75rem;
  z-index: 40;
  display: flex;
  flex-direction: column;
  gap: 0.625rem;
  max-block-size: 60vh;
  overflow-y: auto;
  padding: 0.875rem 1rem;
  border: 1px solid var(--gold-edge);
  border-radius: var(--r-lg);
  background: var(--panel);
  box-shadow: var(--shadow-tomb);
}
@media (min-width: 640px) { .note-sheet { inset-inline-start: auto; inline-size: 24rem; } }
.note-sheet__title { margin: 0; font-size: 0.9375rem; font-weight: 700; color: var(--ink); }
.note-sheet__on, .note-sheet__why { margin: 0.125rem 0 0; font-size: 0.75rem; font-weight: 500; color: var(--sage); overflow-wrap: anywhere; }
.note-sheet__picks { display: flex; flex-wrap: wrap; gap: 0.375rem; }

/* ---- Two views ------------------------------------------------------------
   The board's Tasks/Tickets choice is the one switch (switch.css): across the row on a phone, a compact pair on a
   desk. */
.view-switch { grid-column: 1 / -1; }
.notice--owed.board-block { grid-column: 1 / -1; }

/* ---- A ticket, wherever it is mentioned ------------------------------------
   Its name, its owner and its last note, and nothing else. Anything more is
   on the ticket itself, one tap in. */
.ticket-mention {
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
  min-inline-size: 0;
  text-align: start;
  color: inherit;
}
.ticket-mention__name { font-size: 0.9375rem; font-weight: 700; line-height: 1.35; color: var(--ink-soft); overflow-wrap: anywhere; }
.ticket-mention__owner { font-size: 0.75rem; font-weight: 600; color: var(--sage-mute); }
.ticket-mention__note {
  font-size: 0.8125rem;
  font-weight: 500;
  line-height: 1.4;
  color: var(--ink);
  overflow-wrap: anywhere;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
/* On a task card the ticket's name is already the card's title (K-4), so in the link below it is a label, not a
   second title: the meta line's size and weight. It stays visible: a ticket with no owner and no note would
   otherwise leave the link with nothing in it (the design gate's R10 caught it at 20px wide). */
.task-card .ticket-mention__name { font-size: 0.75rem; font-weight: 600; color: var(--sage-mute); }

/* A tap target like any other: 44px, whatever the ticket's name is (the
   thumb bar's rule, and WCAG 2.5.5's). */
button.ticket-mention--link {
  min-block-size: 44px;
  justify-content: center;
  margin-block-start: 0.375rem;
  padding: 0.375rem 0.625rem;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--panel-raised);
  cursor: pointer;
}
@media (hover: hover) and (pointer: fine) {
button.ticket-mention--link:hover { border-color: var(--gold-edge); }
}
.ticket-card__toggle { flex: 1 1 auto; min-inline-size: 0; color: inherit; text-align: start; background: none; cursor: pointer; }
.running-ribbon .ticket-mention--link, .thumb-bar .ticket-mention--link { margin-block-start: 0.125rem; }

/* ---- Choosing the ticket a task belongs to ----------------------------------- */
.chip-row { display: flex; flex-wrap: wrap; gap: 0.375rem; }
/* The chips flow along the whole row and wrap onto the next; one that is longer than the row wraps inside itself
   rather than running out of the form. */
.chip-row .chip-btn { max-inline-size: 100%; white-space: normal; text-align: start; }
.form-grid > .ticket-choice { grid-column: 1 / -1; }
.ticket-choice__list { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(13rem, 100%), 1fr)); gap: 0.375rem; }
.ticket-choice__opt {
  display: block;
  min-block-size: 44px;
  padding: 0.5rem 0.75rem;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--panel);
  font-weight: 600;
  color: var(--ink);
  text-align: start;
  cursor: pointer;
  transition: background-color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}
.ticket-choice__opt[aria-pressed="true"] {
  border-color: var(--gold-edge);
  background: color-mix(in srgb, var(--gold-500) 8%, var(--panel));
}
.ticket-choice__opt--new { border-style: dashed; color: var(--ink-soft); }
.ticket-choice__new { display: flex; flex-direction: column; gap: 0.625rem; margin-block-start: 0.5rem; }

/* ---- One ticket, in full ---------------------------------------------------- */
.ticket-detail { display: flex; flex-direction: column; gap: 0.875rem; }
.ticket-detail__facts { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0.625rem 1rem; margin: 0; }
@media (max-width: 479px) { .ticket-detail__facts { grid-template-columns: minmax(0, 1fr); } }
.ticket-detail__facts dt { font-size: 0.75rem; font-weight: 600; color: var(--sage-mute); }
.ticket-detail__facts dd { margin: 0.125rem 0 0; font-size: 0.875rem; font-weight: 600; color: var(--ink); overflow-wrap: anywhere; }
.ticket-detail__rename { display: flex; gap: 0.5rem; align-items: stretch; }
.ticket-detail__rename .field-input { flex: 1 1 auto; min-inline-size: 0; }
.ticket-timeline { display: flex; flex-direction: column; gap: 0.5rem; margin: 0; padding: 0; list-style: none; }
.ticket-timeline li { display: flex; flex-direction: column; gap: 0.125rem; padding-inline-start: 0.75rem; border-inline-start: 2px solid var(--line); }
.ticket-timeline__when { font-size: 0.75rem; font-weight: 600; color: var(--sage-mute); }
.ticket-timeline__what { font-size: 0.8125rem; color: var(--ink); overflow-wrap: anywhere; }

/* A figure keeps dir="ltr" so its unit stays on the right side of it (DESIGN.md
   section 8), but inside a flex column that also pins its text to the left edge
   of an RTL card. Sized to its content and started from the parent's own
   direction, it sits where the label above it does. */
.ticket-task__time { unicode-bidi: isolate; }

/* ---- Hover tips ------------------------------------------------------------
   The one tooltip. Shown by tips.js after the pointer has rested 1.5s; never on
   touch. Ink on paper flipped, so it reads on every surface in both themes. */
.tempo-tip {
  position: fixed;
  z-index: 60;
  max-inline-size: 320px;
  padding: 6px 10px;
  border-radius: var(--r-sm);
  background: var(--ink);
  color: var(--bg);
  box-shadow: var(--shadow-2);
  font-size: 0.8125rem;
  line-height: 1.4;
  pointer-events: none;
}

/* ==========================================================================
   TARGET SIZE
   A control is at least 24px on its smaller side everywhere (WCAG 2.2, 2.5.8), and at
   least 44px on a touch screen, where the pointer is a fingertip. Last in the file so it
   holds over the component rules above; each control names itself here rather than
   growing in its own rule, so the one place to read what "big enough" means is this one.
   ========================================================================== */
/* Every button and every disclosure, by element and not by class: a list of classes goes out of
   date the day a component is added (the ticket card's toggle and the settings' link buttons were
   missed that way). A component that wants a bigger target sets its own larger size; none may go
   under this one. */
button,
summary {
  min-block-size: 1.5rem;
  min-inline-size: 1.5rem;
}

.task-card__link {
  display: inline-flex;
  align-items: center;
}

@media (pointer: coarse) {
  button,
  summary {
    min-block-size: 2.75rem;
    min-inline-size: 2.75rem;
  }
}

/* The compact controls (an icon button, an extra-small button, a dialog's close) keep their drawn size on a desk, where
   a row of them reads better small, but what a pointer can hit is the full control height around them: an invisible
   layer centred on the control, never smaller than the control itself (WCAG 2.2 SC 2.5.5, 44 by 44). */
.icon-btn,
.btn--xs,
.close-btn { position: relative; }
.icon-btn::after,
.btn--xs::after,
.close-btn::after {
  content: '';
  position: absolute;
  inset-block: min(0px, calc((100% - var(--control-h)) / 2));
  inset-inline: min(0px, calc((100% - var(--control-h)) / 2));
}

/* ==========================================================================
   A ticking number holds its width in Arabic (R14, idle stability)
   ==========================================================================
   `font-variant-numeric: tabular-nums` does nothing for Arabic-Indic digits: IBM Plex Sans Arabic, the face that draws them
   ('Tempo Arabic' above), has no tnum or pnum feature, and its digits are 0.263em (٠) to 0.635em (٣) wide (measured from
   the woff2 files: GSUB features are calt, ccmp, fina, init, locl, medi, rlig; U+0660..0669 advances differ). So every
   change of a digit could change the width of the reading, and the boxes beside it moved on each tick. The Latin digits
   (DM Mono) are all 0.6em, which is why English never moved.
   So the width cannot come from the glyphs. Each ticking reading reserves the width of its widest possible value: the widest
   digit (0.635em, at weight 700) for each of its digits, plus DM Mono's colon (0.6em), so it never changes:
     hh:mm     4 digits + 1 colon  = 3.14em     the clock
     hh:mm:ss  6 digits + 2 colons = 5.01em     the timers
     (.timer-chip--shift keeps its own, wider, min-inline-size above.)
   Plus a pixel per glyph. Where text is hinted (Linux, the CI image) each glyph's advance is rounded to a whole pixel,
   not left at 0.635em: the widest digit, ٣, drew 10px, and a reading came out up to 1.1px wider than the reserve.
   Rounding to the nearest pixel moves a glyph by at most 0.5px (allow a whole one), so n glyphs can exceed the ideal
   sum by at most n px: 5px for hh:mm (4 digits + colon), 8px for hh:mm:ss (6 digits + 2 colons). The reserve is the ideal
   width plus that, so it holds however the text is drawn (measured in the image: 0.84px and 1.09px over).
   In Arabic only ([dir="rtl"]): the Latin readings are already tabular. */
:root {
  --digit-w: 0.635em;
  --colon-w: 0.6em;
  --glyph-slack: 1px;   /* the most hinting can add to one glyph's advance (see above) */
  --reading-hm: calc(4 * (var(--digit-w) + var(--glyph-slack)) + (var(--colon-w) + var(--glyph-slack)));
  --reading-hms: calc(6 * (var(--digit-w) + var(--glyph-slack)) + 2 * (var(--colon-w) + var(--glyph-slack)));
}
[dir="rtl"] .hero-clock .num,
[dir="rtl"] .stage__clock {
  display: inline-block;   /* a span is inline, and an inline box ignores min-inline-size */
  min-inline-size: var(--reading-hm);
}
[dir="rtl"] .timer-chip--live,
[dir="rtl"] .running-ribbon__timer,
[dir="rtl"] .thumb-bar__timer,
[dir="rtl"] .stat-card__value.num,
[dir="rtl"] .stage__timer,
[dir="rtl"] .stage__stat-value,
[dir="rtl"] .stage__row-time {
  min-inline-size: var(--reading-hms);
}
[dir="rtl"] .stage__row-time,
[dir="rtl"] .stage__stat-value {
  display: inline-block;   /* spans: an inline box ignores min-inline-size */
}
/* A stat card is a fixed-width grid cell, and the reserved reading may not be wider than the card that holds it. On a 390px
   phone in Arabic the hh:mm:ss reservation (128px) was wider than the card's 109px and widened the page by 13px whenever a
   shift was running (found once the browser specs stood on a fixed instant with a shift active; tests/visual.spec.js).
   Capping the reservation at the card (min(reserve, 100%)) stopped the overflow but not the movement: the digits, wider
   than the box, still overflowed it by an amount that followed the digits, and that moved everything fixed to the page
   edge (the thumb bar) on every tick (R14). So the reading is made to fit instead: the card is a size container, and the
   figure steps down the type scale (24, 20, 17, 15, 14, 13, 12px) whenever the card's content width is too narrow to hold a
   whole reservation (5.01em + 8 * the glyph slack) at the size above, so there is no overflow for a digit to change. A
   step is used rather than a computed size so the design gate's scale rule (R3) holds; each threshold is 5.01 * size + 8,
   rounded up, for the size above it. */
.stat-card {
  container-type: inline-size;
}
@media (min-width: 768px) {
  @container (max-width: 159px) { [dir="rtl"] .stat-card__value.num { font-size: 24px; } }
  @container (max-width: 129px) { [dir="rtl"] .stat-card__value.num { font-size: 20px; } }
}
@container (max-width: 109px) { [dir="rtl"] .stat-card__value.num { font-size: 17px; } }
@container (max-width: 94px) { [dir="rtl"] .stat-card__value.num { font-size: 15px; } }
@container (max-width: 84px) { [dir="rtl"] .stat-card__value.num { font-size: 14px; } }
@container (max-width: 79px) { [dir="rtl"] .stat-card__value.num { font-size: 13px; } }
@container (max-width: 74px) { [dir="rtl"] .stat-card__value.num { font-size: 12px; } }

/* --- the start prompt: a task is running and another is being started ------------------------------------------------
   One heading, then groups of icon + short-label buttons: the running task (name, then what happens to it), the new
   task, and last "Keep both going". Words that do not fit wrap inside their button rather than push the dialog wider. */
.start-prompt__group { display: grid; gap: 0.5rem; }
.start-prompt__name { margin: 0; min-width: 0; overflow-wrap: anywhere; font-size: 0.8125rem; color: var(--ink-soft, inherit); }
.start-prompt__kind { opacity: 0.75; }
.start-prompt__row { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.start-prompt__btn { flex: 1 1 8rem; min-width: 0; white-space: normal; text-align: center; }
.start-prompt__btn--wide { flex-basis: 100%; }
.parallel-input { width: 5rem; }

/* More running tasks than a phone has room for: the bars at the bottom scroll inside a capped height instead of
   covering the page. */
@media (max-width: 767px) {
  .thumb-stack { max-height: 14rem; overflow-y: auto; overscroll-behavior: contain; }
}

/* The wrapper that carries a disabled control's reason (a disabled button gets no hover or focus events). */
.btn-tipwrap { display: inline-flex; border-radius: var(--r-sm); }
/* Some engines (Firefox) do not pass a disabled button's pointer events up to its wrapper: let them land on the wrapper. */
.btn-tipwrap > .btn:disabled { pointer-events: none; }
.btn-tipwrap[tabindex] { cursor: not-allowed; }
/* The Start shift wrapper (L-15) sits where the button did: the 1rem clearance above is Emergency's, not its. */
.topbar-actions > .btn-tipwrap--shift { margin-inline-start: 0; }

/* Pause reasons (D6): twelve presets with icons, one tap each, in as many columns as fit; a long label wraps inside
   its chip rather than widening the dialog. Each is a full finger target. */
.pause-reasons { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(10rem, 100%), 1fr)); gap: 0.375rem; }
.pause-reasons .chip-btn {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  min-block-size: var(--control-h);
  white-space: normal;
  text-align: start;
  border-radius: var(--r-md);
}
.pause-reasons .chip-btn .icon-sm { flex: none; }

/* A snackbar that offers two things (Resume X, Add note) wraps onto a second line rather than run off a phone. */
.toast { flex-wrap: wrap; }
.toast > span { flex: 1 1 10rem; min-inline-size: 0; overflow-wrap: anywhere; }
