/* Auto-extracted from _theme_vars.html + _chrome_styles.html.
   Shared nav/chrome + theme tokens, served cached (see handle_static). */

/* --- Self-hosted type -------------------------------------------------------
   38 stacks name "Source Serif Pro" and 26 name "Source Sans Pro", and nothing
   loaded either, so every heading fell back to Georgia and every UI string to
   Segoe UI. The five faces below are real files under /static/fonts.

   The last four rules are a BRIDGE: they point the two legacy names at the same
   files, so all 64 existing stacks render a loaded face with no template edits.
   New code should prefer --font-display / --font-body.

   Licences live beside the files (OFL-Fraunces.txt, OFL-IBM-Plex.txt); SIL OFL
   1.1 requires them to travel with the fonts. There is no monospace face
   because no stack in this application asks for one. */
@font-face { font-family: "Fraunces"; src: url("/static/fonts/fraunces-var.woff2") format("woff2"); font-weight: 100 900; font-style: normal; font-display: swap; }
@font-face { font-family: "Fraunces"; src: url("/static/fonts/fraunces-var-italic.woff2") format("woff2"); font-weight: 100 900; font-style: italic; font-display: swap; }
@font-face { font-family: "IBM Plex Sans"; src: url("/static/fonts/plex-sans-400.woff2") format("woff2"); font-weight: 400; font-style: normal; font-display: swap; }
@font-face { font-family: "IBM Plex Sans"; src: url("/static/fonts/plex-sans-500.woff2") format("woff2"); font-weight: 500; font-style: normal; font-display: swap; }
@font-face { font-family: "IBM Plex Sans"; src: url("/static/fonts/plex-sans-600.woff2") format("woff2"); font-weight: 600; font-style: normal; font-display: swap; }
@font-face { font-family: "Source Serif Pro"; src: url("/static/fonts/fraunces-var.woff2") format("woff2"); font-weight: 100 900; font-style: normal; font-display: swap; }
@font-face { font-family: "Source Sans Pro"; src: url("/static/fonts/plex-sans-400.woff2") format("woff2"); font-weight: 100 450; font-style: normal; font-display: swap; }
@font-face { font-family: "Source Sans Pro"; src: url("/static/fonts/plex-sans-500.woff2") format("woff2"); font-weight: 451 550; font-style: normal; font-display: swap; }
@font-face { font-family: "Source Sans Pro"; src: url("/static/fonts/plex-sans-600.woff2") format("woff2"); font-weight: 551 900; font-style: normal; font-display: swap; }

:root {
  --font-display: "Fraunces", Georgia, "Times New Roman", serif;
  --font-body: "IBM Plex Sans", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;

  --tk-blue-950: #0B1120;
  --tk-blue-900: #10182A;
  --tk-blue-800: #18233A;
  --tk-blue-700: #202D48;
  --tk-blue-600: #2A3A58;
  --tk-blue-500: #3A506F;
  --tk-blue-400: #587291;
  --tk-blue-accent: #65B6DE;
  --tk-gallery-canvas: #E7EBF0;
  --tk-gallery-surface: #EDF0F3;
  --tk-gallery-ink: #18233A;
  --tk-gallery-muted: #56647A;
  --tk-gallery-line: rgba(24, 35, 58, 0.2);
  --tk-modal-backdrop: rgba(218, 228, 241, 0.62);
  --tk-parchment: #C5A57C;
  --tk-parchment-deep: #B28D63;
  --tk-tan-soft: #E4D5C1;

  --tk-brown-900: #2A1B12;
  --tk-brown-800: #3B271B;
  --tk-brown-700: #4A3425;
  --tk-brown-600: #5B3D2D;
  --tk-brown-500: #6A4B37;
  --tk-brown-400: #7A5540;
  --tk-brown-300: #8B6A52;
  --tk-brown-200: #8F674F;
  --tk-brown-muted: #866C5A;

  /* Universal application surfaces: the Archive Explorer palette is the standard. */
  --tk-bg: var(--tk-gallery-canvas);
  --tk-bg-soft: var(--tk-gallery-surface);
  --tk-bg-panel: var(--tk-gallery-canvas);
  --tk-bg-card: var(--tk-gallery-surface);
  --tk-hover-fill: rgba(197, 165, 124, 0.18);
  --tk-surface-glass: rgba(16, 24, 42, 0.96);
  --tk-surface-translucent: rgba(24, 35, 58, 0.9);

  --tk-text: var(--tk-gallery-ink);
  --tk-text-secondary: #35445C;
  --tk-text-muted: var(--tk-gallery-muted);
  --tk-text-inverse: #F7EFE3;

  --page: var(--tk-bg);
  --bg: var(--tk-bg);
  --paper: var(--tk-bg-panel);
  --paper-strong: var(--tk-bg-card);
  --ink: var(--tk-text);
  --muted: var(--tk-text-muted);
  --accent: var(--tk-parchment-deep);
  /* Links, and the deep end of the accent gradient. NOT --tk-gallery-ink: this
     token colours 124 sites, most of them links, and while it pointed at the ink
     a link and the sentence around it were the same #18233A, told apart only by
     font-weight. 6.23:1 on the canvas, and inverse text still clears 6.5:1 where
     it is used as a background. */
  --accent-deep: #1F5A7D;
  --accent-soft: rgba(197, 165, 124, 0.2);
  --line: var(--tk-gallery-line);
  --line-soft: rgba(24, 35, 58, 0.1);
  --danger: #7B2E22;
  --warning: #8A5A28;
  --gold: #D8AD79;
  --selected: var(--tk-parchment);
  --glass: rgba(231, 235, 240, 0.96);
  --hero: linear-gradient(135deg, #0B1120 0%, #10182A 48%, #202D48 100%);
  --shadow: 0 18px 45px rgba(24, 35, 58, 0.14);

  --blue: var(--tk-blue-accent);
  --green: #83B79A;
  --red: var(--danger);
}

/* --- Accessibility basics, global on purpose --------------------------------
   These live HERE, beside the tokens, rather than in _chrome_styles.html,
   because this is the one file every page reaches: 20 templates get it through
   chrome.css, 6 inline _chrome_styles.html (which includes this at its line 1),
   and login.html and landing.html include it directly. Put in the chrome partial
   instead, they missed login.html entirely -- the first page every user meets,
   which then had no focus ring, no reduced-motion reset, and its own
   `input:focus { outline: none }` with nothing to fall back to.

   !important on the motion reset is load-bearing, though not for the reason first
   recorded here. The three prep stations do NOT link chrome.css at all -- they
   only include _chrome_styles.html, which pulls this file in at the TOP
   of their own <style>, so every page-local animation rule below it wins on source
   order. On the 20 templates that do link chrome.css, the <link> comes AFTER their
   inline <style>. Either way a rule that relies on order alone applies on only
   some pages. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}

/* TWO-TONE, because one colour cannot clear 3:1 on every surface this app has.
   A dark ring carries the contrast on the light canvas and on parchment; the
   light halo carries it on the near-black nav. WCAG 2.2 SC 1.4.11 asks 3:1 of a
   focus indicator, and the parchment accent used here previously measured
   2.55:1 on the canvas and 1.31:1 on a selected parchment card. */
:focus-visible {
  outline: 2px solid var(--tk-gallery-ink);
  outline-offset: 2px;
  box-shadow: 0 0 0 4px var(--tk-text-inverse);
  border-radius: 3px;
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 1000;
  padding: 0.7rem 1.1rem;
  background: var(--tk-gallery-canvas);
  color: var(--tk-gallery-ink);
  border: 1px solid var(--tk-gallery-line);
  border-radius: 0 0 4px 0;
  font-weight: 600;
  text-decoration: none;
}
.skip-link:focus {
  left: 0;
}

      /* THE HEIGHT OF THE BAR, AS A NUMBER EVERY PAGE CAN READ. `--tk-nav-height` below is the
         chrome's own name for it, but it lives on `.site-nav`, and the pages that need it are not
         inside the bar. So four of them guessed instead: archive_list, jobs, timekeeper and
         customer_approvals wrote `48px` outright or read a `--tk-header-height` that nothing
         defined. Declared once here, the bar and the pages can no longer disagree. */
      :root {
        --tk-header-height: 160px;
      }


      /* The chrome states its own box model instead of depending on each page providing a
         `* { box-sizing: border-box }` reset. Two pages do not provide one, and there
         .nav-inner's 20px of horizontal padding was added to its 100% width -- holding the
         document 20px wider than the screen at every size, which on a phone is enough to make
         the browser shrink the whole page. Scoped to the chrome's own elements rather than a
         global reset, so no page's own layout changes. */
      .site-nav,
      .nav-inner,
      .nav-menu,
      .nav-menu-group,
      .nav-dropdown,
      .site-footer,
      .footer-inner {
        box-sizing: border-box;
      }

      /* THE PHONE SHEET'S OWN FURNITURE IS HIDDEN UNTIL THERE IS A PHONE. Everything that makes
         the nav a sheet -- the Menu button that opens it, and the "Menu x" bar inside it -- was
         styled ONLY inside `@media (max-width: 700px)`, and nothing declared it hidden anywhere
         else. A rule that does not exist outside a media query hides nothing outside it: above
         700px the button and the close bar fell back to browser defaults and rendered as plain
         buttons, so the desktop header showed "Menu" and "Menu x" sitting beside the very
         dropdowns they exist to replace.

         Declared at the top level so the default is HIDDEN and the media query is what turns them
         on -- the way round that fails safe if a breakpoint ever moves. */
      .nav-menu-toggle,
      .nav-sheet-head {
        display: none;
      }

      .site-nav {
        /* One header on every page. The medallion sits in normal flow and the bar is tall
           enough to hold it whole, so nothing is clipped and nothing shifts between tabs.
           Change the two sizes here and the whole header follows. */
        --tk-medallion-size: 136px;
        --tk-nav-height: var(--tk-header-height);
        --tk-nav-rail-width: 340px;
        --tk-bg: var(--tk-blue-950);
        --tk-bg-soft: var(--tk-blue-900);
        --tk-bg-panel: var(--tk-blue-800);
        --tk-bg-card: var(--tk-blue-700);
        --tk-hover-fill: var(--tk-blue-600);
        --tk-text: #F4EBDD;
        --tk-text-muted: #A9B1C2;
        --ink: var(--tk-text);
        --muted: var(--tk-text-muted);
        --line: rgba(218, 228, 241, 0.16);
        --accent: #B9825E;
        --accent-deep: #D5A878;
        --danger: #E38A80;
        border-bottom: 1px solid var(--line);
        background: var(--tk-surface-glass);
        box-shadow: 0 8px 24px rgba(2, 7, 18, 0.24);
        position: relative;
        z-index: 60;
        height: var(--tk-nav-height);
        min-height: var(--tk-nav-height);
        overflow: visible;
      }

      .site-nav::after {
        content: none;
      }

      /* Keep page content flush with the navigation; do not expose a canvas-colored band below it. */
      body > .site-nav + :is(main, .shell, .page, .portal-shell, .landing-main) {
        margin-top: 0 !important;
        padding-top: 0 !important;
      }

      .nav-inner,
      .footer-inner {
        max-width: 1500px;
        margin: 0 auto;
        padding: 12px 22px;
      }

      .nav-inner {
        position: relative;
        display: flex;
        /* The medallion and the links share one horizontal centre line. */
        align-items: center;
        justify-content: flex-start;
        gap: 16px;
        width: 100%;
        height: var(--tk-nav-height);
        max-width: none;
        margin: 0;
        padding: 0 16px;
        z-index: 1;
      }

      .brand {
        display: inline-flex;
        align-items: center;
        gap: 14px;
        min-width: 220px;
        color: var(--ink);
        text-decoration: none;
      }

      .brand img {
        display: block;
        width: 156px;
        max-width: 40vw;
        border-radius: 10px;
      }

      .brand-name {
        display: grid;
        gap: 1px;
        line-height: 1;
      }

      .brand-name strong {
        color: var(--ink);
        font-size: 1.12rem;
        font-weight: 900;
      }

      .brand-name span {
        color: var(--muted);
        font-size: 0.78rem;
        font-weight: 700;
      }

      /* In normal flow, not absolutely positioned. Taking it out of flow is what let the
         136px medallion hang out of a 48px bar and get clipped, and what forced every long
         page to opt into a taller header of its own. */
      .task-node-wrap {
        position: relative;
        z-index: 100;
        flex: 0 0 auto;
        display: flex;
        align-items: center;
      }

      .task-node {
        --task-progress: 0%;
        position: relative;
        width: var(--tk-medallion-size);
        height: var(--tk-medallion-size);
        display: grid;
        place-items: center;
        border: 0;
        border-radius: 50%;
        padding: 10px;
        background: transparent;
        cursor: pointer;
      }

      .task-node-art {
        position: relative;
        z-index: 2;
        /* The button carries 10px of padding, so the art is the medallion less both sides.
           Pinning it to a fixed px is what made the coin overflow its own button. */
        width: calc(var(--tk-medallion-size) - 20px);
        height: calc(var(--tk-medallion-size) - 20px);
        overflow: hidden;
        border: 2px solid rgba(216, 188, 151, 0.54);
        border-radius: 50%;
        background: var(--tk-bg-soft);
        box-shadow: 0 6px 16px rgba(2, 7, 18, 0.38);
      }

      .task-node-art img {
        width: 100%;
        height: 100%;
        display: block;
        object-fit: cover;
        object-position: center;
        filter: sepia(0.14) saturate(0.92) brightness(1.08);
        transform: scale(1.7);
      }

      .task-node-orbit {
        position: absolute;
        inset: 0;
        z-index: 1;
        border-radius: 50%;
        opacity: 0;
        background: conic-gradient(#57baf0 0 var(--task-progress), transparent var(--task-progress) 100%);
        filter: drop-shadow(0 0 5px rgba(61, 174, 234, 0.9));
        transition: opacity 160ms ease;
      }

      .task-node-orbit::after {
        content: "";
        position: absolute;
        inset: 8px;
        border-radius: 50%;
        background: var(--tk-bg);
      }

      .task-node.active .task-node-orbit { opacity: 1; }
      .task-node.indeterminate .task-node-orbit {
        background: conic-gradient(from 0deg, transparent 0 70%, #71c7f4 86%, #2f98cf 94%, transparent 100%);
        animation: task-orbit-spin 1.15s linear infinite;
      }

      @keyframes task-orbit-spin { to { transform: rotate(360deg); } }

      .task-node:focus-visible {
        outline: 3px solid rgba(73, 157, 203, 0.5);
        outline-offset: 2px;
      }

      .task-node-count {
        position: absolute;
        right: -2px;
        top: -1px;
        z-index: 3;
        min-width: 21px;
        height: 21px;
        display: grid;
        place-items: center;
        border: 2px solid var(--tk-bg);
        border-radius: 999px;
        padding: 0 4px;
        background: #238cc5;
        color: #fff;
        font-size: 0.68rem;
        font-weight: 900;
      }

      .task-node-count[hidden] { display: none; }

      .task-node-popover {
        position: absolute;
        left: 0;
        /* Anchored to the medallion rather than a hard-coded header height, so it follows
           whatever --tk-medallion-size is set to. */
        top: calc(100% + 8px);
        z-index: 110;
        width: min(430px, calc(100vw - 28px));
        max-height: min(620px, calc(100dvh - 100px));
        display: none;
        grid-template-rows: auto minmax(0, 1fr) auto;
        overflow: hidden;
        border: 1px solid var(--line);
        border-radius: 10px;
        background: var(--tk-bg-soft);
        color: var(--tk-text-inverse);
        box-shadow: 0 22px 55px rgba(2, 7, 18, 0.48);
      }

      .task-node-popover.open { display: grid; }

      .timekeeper-busy-overlay {
        position: fixed;
        inset: 0;
        z-index: 10000;
        display: grid;
        place-content: center;
        justify-items: center;
        gap: 16px;
        background: rgba(4, 15, 31, 0.28);
        backdrop-filter: blur(2px);
        cursor: wait;
      }

      .timekeeper-busy-overlay[hidden] { display: none; }

      .timekeeper-busy-indicator {
        position: relative;
        width: 150px;
        height: 150px;
        display: grid;
        place-items: center;
      }

      .timekeeper-busy-art {
        position: relative;
        z-index: 2;
        width: 126px;
        height: 126px;
        overflow: hidden;
        border: 2px solid rgba(216, 188, 151, 0.7);
        border-radius: 50%;
        background: var(--tk-bg-soft);
        box-shadow: 0 12px 34px rgba(2, 7, 18, 0.48);
      }

      .timekeeper-busy-art img {
        width: 100%;
        height: 100%;
        display: block;
        object-fit: cover;
        object-position: center;
        filter: sepia(0.14) saturate(0.92) brightness(1.08);
        transform: scale(1.7);
      }

      .timekeeper-busy-orbit {
        position: absolute;
        inset: 0;
        z-index: 1;
        border-radius: 50%;
        background: conic-gradient(from 0deg, transparent 0 70%, #71c7f4 86%, #2f98cf 94%, transparent 100%);
        filter: drop-shadow(0 0 8px rgba(61, 174, 234, 0.95));
        animation: task-orbit-spin 1.05s linear infinite;
      }

      .timekeeper-busy-orbit::after {
        content: "";
        position: absolute;
        inset: 9px;
        border-radius: 50%;
        background: var(--tk-bg);
      }

      .timekeeper-busy-overlay strong {
        border: 1px solid rgba(216, 188, 151, 0.54);
        border-radius: 999px;
        padding: 9px 16px;
        background: var(--tk-bg-soft);
        color: var(--tk-text);
        box-shadow: 0 8px 24px rgba(2, 7, 18, 0.3);
        font-size: 1rem;
      }
      .task-popover-header,
      .task-popover-footer { padding: 13px 14px; }
      .task-popover-header {
        display: flex;
        align-items: flex-start;
        justify-content: space-between;
        gap: 12px;
        border-bottom: 1px solid var(--line);
      }
      .task-popover-header > div { display: grid; gap: 2px; }
      .task-popover-header strong {
        color: var(--tk-text-inverse);
        font: 800 1.05rem/1.1 "Source Serif Pro", Georgia, serif;
      }
      .task-popover-header span { color: var(--muted); font-size: 0.8rem; }
      .task-popover-close {
        border: 0; padding: 0 3px; background: transparent; color: var(--muted);
        font-size: 1.35rem; cursor: pointer;
      }
      .task-popover-body { min-height: 80px; overflow: auto; padding: 8px 14px; }
      .task-empty { margin: 18px 0; color: var(--muted); text-align: center; }
      .task-card { position: relative; display: grid; gap: 7px; padding: 11px 0; border-bottom: 1px solid var(--line); }
      .task-card:last-child { border-bottom: 0; }
      .task-card-heading,
      .task-card-meta { display: flex; justify-content: space-between; gap: 12px; }
      .task-card-heading strong { color: var(--tk-text-inverse); }
      .task-card-heading span { color: var(--tk-blue-accent); font-size: 0.76rem; font-weight: 900; }
      .task-card-meta,
      .task-card small { color: var(--muted); font-size: 0.78rem; }
      .task-card small { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
      .task-card-progress { height: 5px; overflow: hidden; border-radius: 999px; background: rgba(218, 228, 241, 0.1); }
      .task-card-progress span { display: block; width: var(--progress); height: 100%; background: #49aade; }
      .task-cancel { justify-self: end; border: 0; background: transparent; color: var(--danger); font-weight: 800; cursor: pointer; }
      .task-popover-footer { display: flex; justify-content: flex-end; border-top: 1px solid var(--line); }
      .task-popover-footer .button { min-height: 36px; padding: 8px 12px; border-radius: 7px; text-decoration: none; font-weight: 850; }

      .nav-menu,
      .footer-inner,
      .footer-inner div,
      .footer-inner nav {
        display: flex;
        align-items: center;
        gap: 12px;
      }

      .nav-menu {
        flex: 1 1 auto;
        flex-wrap: nowrap;
        /* Centred in the bar. The old rule pushed the links past a 340px rail to dodge the
           absolutely-positioned medallion; the medallion is in flow now, so the links simply
           take the space that is left and sit in the middle of it. */
        justify-content: center;
        gap: 7px;
        margin-left: 0;
        min-width: 0;
        color: var(--muted);
        font-weight: 800;
      }

      .nav-menu-group {
        position: relative;
      }

      .nav-menu-trigger {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        gap: 8px;
        min-height: 32px;
        border: 1px solid var(--line);
        border-radius: 7px;
        padding: 6px 9px;
        background: var(--tk-bg-panel);
        color: var(--ink);
        font-size: 0.82rem;
        font-weight: 850;
        line-height: 1;
        text-decoration: none;
        cursor: pointer;
      }

      .nav-menu-trigger:hover,
      .nav-menu-group:hover > .nav-menu-trigger,
      .nav-menu-group.open > .nav-menu-trigger {
        border-color: var(--accent);
        background: var(--tk-hover-fill);
        color: var(--tk-text);
      }

      .nav-menu-trigger.active {
        border-color: var(--tk-parchment-deep);
        background: var(--tk-parchment);
        color: var(--tk-gallery-ink);
      }

      .nav-caret {
        width: 0;
        height: 0;
        border-left: 4px solid transparent;
        border-right: 4px solid transparent;
        border-top: 5px solid currentColor;
      }

      .nav-dropdown {
        position: absolute;
        top: calc(100% + 8px);
        left: 0;
        z-index: 80;
        min-width: 210px;
        display: grid;
        gap: 4px;
        padding: 8px;
        border: 1px solid var(--line);
        border-radius: 8px;
        background: var(--tk-bg-soft);
        box-shadow: 0 18px 44px rgba(42, 27, 18, 0.2);
        box-sizing: border-box;
        overflow: hidden;
        opacity: 0;
        pointer-events: none;
        transform: translateY(-4px);
        transition: opacity 110ms ease, transform 110ms ease;
      }

      .nav-menu > :last-child .nav-dropdown {
        right: 0;
        left: auto;
      }

      .nav-dropdown::before {
        content: "";
        position: absolute;
        inset: -10px 0 auto 0;
        height: 10px;
      }

      .nav-menu-group.open > .nav-dropdown {
        opacity: 1;
        pointer-events: auto;
        transform: translateY(0);
      }

      .nav-dropdown-item,
      .nav-dropdown-label {
        box-sizing: border-box;
        width: 100%;
        display: flex;
        align-items: center;
        min-height: 36px;
        border: 0;
        border-radius: 6px;
        padding: 8px 10px;
        background: transparent;
        color: var(--ink);
        font: inherit;
        font-size: 0.9rem;
        font-weight: 850;
        text-align: left;
        text-decoration: none;
        white-space: nowrap;
      }

      .nav-dropdown-item {
        cursor: pointer;
      }

      .nav-dropdown-item:hover,
      .nav-dropdown-item:focus {
        outline: none;
        background: var(--tk-hover-fill);
        color: var(--tk-text);
      }

      .nav-dropdown-item.active {
        outline: none;
        background: var(--tk-parchment);
        color: var(--tk-gallery-ink);
      }

      .nav-dropdown-item:disabled {
        opacity: 0.45;
        cursor: not-allowed;
      }

      .nav-dropdown-danger { color: var(--danger); }

      .nav-dropdown-separator {
        height: 1px;
        margin: 4px 6px;
        background: var(--line);
      }

      .nav-dropdown-label {
        color: var(--muted);
        cursor: default;
      }

      .archive-explorer-dropdown {
        width: max-content;
        min-width: 280px;
        max-width: min(620px, calc(100vw - 24px));
      }
      #archive-menu-list {
        width: max-content;
        min-width: 100%;
        max-width: 100%;
        max-height: min(520px, calc(100dvh - 90px));
        display: grid;
        gap: 4px;
        overflow-x: hidden;
        overflow-y: auto;
      }
      .archive-explorer-dropdown .nav-dropdown-item {
        width: 100%;
        max-width: 100%;
        white-space: normal;
        overflow-wrap: anywhere;
      }

      .nav-dropdown-form,
      .logout-form,
      .status-form {
        margin: 0;
      }

      .nav-dropdown-form {
        width: 100%;
      }

      button.primary,
      .button.primary {
        border-color: var(--tk-parchment-deep);
        background: var(--tk-parchment);
        color: var(--tk-gallery-ink);
      }

      button.primary:hover,
      .button.primary:hover,
      button.primary:focus-visible,
      .button.primary:focus-visible {
        border-color: var(--tk-parchment-deep);
        background: var(--tk-parchment-deep);
        color: var(--tk-gallery-ink);
      }

      input,
      select,
      textarea {
        border-color: var(--line);
        background: var(--tk-bg-soft);
        color: var(--tk-text);
      }

      input::placeholder,
      textarea::placeholder {
        color: var(--tk-text-muted);
      }

      .global-import-strip {
        border-top: 1px solid var(--line);
        background: rgba(217, 196, 173, 0.78);
      }

      .global-download-strip {
        background: rgba(234, 238, 232, 0.86);
      }

      .global-import-button {
        width: min(1500px, calc(100% - 44px));
        margin: 0 auto;
        display: grid;
        grid-template-columns: minmax(180px, auto) minmax(120px, 1fr) auto;
        gap: 12px;
        align-items: center;
        border: 0;
        padding: 9px 0;
        background: transparent;
        color: var(--ink);
        text-align: left;
        cursor: pointer;
      }

      .global-import-title,
      .global-import-percent {
        font-weight: 900;
        white-space: nowrap;
      }

      .global-import-phase {
        min-width: 0;
        overflow: hidden;
        color: var(--muted);
        font-size: 0.9rem;
        font-weight: 800;
        text-overflow: ellipsis;
        white-space: nowrap;
      }

      .global-import-progress {
        height: 8px;
        min-width: 120px;
        overflow: hidden;
        border-radius: 999px;
        background: rgba(218, 228, 241, 0.12);
      }

      .global-import-progress span {
        display: block;
        width: var(--progress, 0%);
        height: 100%;
        border-radius: inherit;
        background: var(--accent);
      }

      .global-download-strip .global-import-progress span {
        background: #3f7f72;
      }

      .global-import-progress.indeterminate span {
        width: 42%;
        animation: archive-import-progress 1.15s ease-in-out infinite alternate;
      }

      @keyframes archive-import-progress {
        from {
          transform: translateX(-75%);
        }

        to {
          transform: translateX(150%);
        }
      }

      .global-import-modal-backdrop {
        position: fixed;
        inset: 0;
        z-index: 70;
        display: none;
        align-items: center;
        justify-content: center;
        padding: 22px;
        background: var(--tk-modal-backdrop);
      }

      .global-import-modal-backdrop.open {
        display: flex;
      }

      .global-import-modal {
        width: min(760px, 96vw);
        max-height: 88dvh;
        display: grid;
        grid-template-rows: auto minmax(0, 1fr) auto;
        overflow: hidden;
        border: 1px solid var(--line);
        border-radius: 8px;
        background: var(--paper, var(--tk-bg-panel));
        box-shadow: 0 28px 70px rgba(42, 27, 18, 0.24);
      }

      .global-import-modal header,
      .global-import-modal footer {
        padding: 16px;
        border-bottom: 1px solid var(--line);
      }

      .global-import-modal footer {
        display: flex;
        flex-wrap: wrap;
        gap: 10px;
        justify-content: flex-end;
        border-top: 1px solid var(--line);
        border-bottom: 0;
      }

      .global-import-modal-body {
        min-height: 0;
        overflow: auto;
        padding: 16px;
      }

      .global-import-modal h2 {
        margin: 0;
        font-size: 1.4rem;
      }

      .global-import-modal .button {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        min-height: 40px;
        border: 1px solid var(--line);
        border-radius: 7px;
        padding: 9px 14px;
        background: var(--tk-bg-soft);
        color: var(--ink);
        font: inherit;
        font-weight: 850;
        text-decoration: none;
        cursor: pointer;
      }

      .global-import-modal .button.primary {
        border-color: var(--tk-parchment-deep);
        background: var(--tk-parchment);
        color: var(--tk-gallery-ink);
      }

      .global-import-modal .button.danger {
        border-color: rgba(123, 46, 34, 0.38);
        color: var(--danger);
      }

      .global-import-stat-grid {
        display: grid;
        grid-template-columns: repeat(4, minmax(0, 1fr));
        gap: 10px;
        margin-top: 14px;
      }

      .global-import-stat {
        border: 1px solid var(--line);
        border-radius: 7px;
        padding: 11px;
        background: var(--tk-bg-soft);
        color: var(--muted);
        font-weight: 800;
      }

      .global-import-stat strong {
        display: block;
        margin-top: 4px;
        color: var(--ink);
        font-size: 1.2rem;
      }

      .global-import-detail-list {
        display: grid;
        gap: 8px;
        margin-top: 14px;
      }

      .global-import-detail-list div {
        display: grid;
        grid-template-columns: 140px minmax(0, 1fr);
        gap: 10px;
        border-bottom: 1px solid var(--line);
        padding-bottom: 8px;
      }

      .global-import-detail-list dt {
        color: var(--muted);
        font-weight: 850;
      }

      .global-import-detail-list dd {
        min-width: 0;
        margin: 0;
        overflow-wrap: anywhere;
      }

      .site-footer {
        --ink: #F4EBDD;
        --muted: #A9B1C2;
        --accent-deep: #D5A878;
        --line: rgba(218, 228, 241, 0.16);
        border-top: 1px solid var(--line);
        background: rgba(24, 35, 58, 0.92);
        color: var(--muted);
      }

      .footer-inner {
        justify-content: space-between;
        flex-wrap: wrap;
      }

      .footer-inner div,
      .footer-inner nav {
        flex-wrap: wrap;
      }

      .footer-inner a {
        color: var(--accent-deep);
        font-weight: 800;
        text-decoration: none;
      }

      /* Universal empty-result messaging sits directly on the current page canvas. */
      .empty,
      .empty-state {
        background: transparent !important;
        color: var(--tk-text-secondary, var(--ink)) !important;
      }

      @media (max-width: 980px) {
        :root {
          --tk-header-height: 72px;
        }

        /* A narrow screen shrinks the medallion rather than clipping it, and the header
           follows because both come from the same two variables. */
        .site-nav {
          --tk-medallion-size: 64px;
          --tk-nav-height: var(--tk-header-height);
          --tk-nav-rail-width: 148px;
        }

        .nav-inner {
          display: flex;
          gap: 10px;
          padding: 0 10px;
        }

        .nav-menu {
          justify-content: center;
          gap: 5px;
          margin-left: 0;
          overflow-x: auto;
        }

        .nav-menu-trigger { padding-inline: 7px; font-size: .76rem; }

        .global-import-button {
          width: calc(100% - 44px);
          grid-template-columns: 1fr auto;
        }

        .global-import-phase,
        .global-import-progress {
          grid-column: 1 / -1;
        }

        .global-import-stat-grid {
          grid-template-columns: repeat(2, minmax(0, 1fr));
        }
      }

      @media (max-width: 700px) {
        .task-node-popover { position: fixed; left: 14px; right: 14px; top: calc(var(--tk-nav-height) + 8px); width: auto; }
        .brand {
          min-width: 0;
        }

        .brand img {
          width: 132px;
        }

        .brand-name {
          display: none;
        }

        /* This block used to take the trigger DOWN to 30px, which is the opposite of what a
           finger needs. The text may stay small; the hit area may not. */
        .nav-menu-trigger {
          min-height: 44px;
          padding: 6px 10px;
          font-size: 0.72rem;
        }

        /* `min-width: min(260px, ...)` reads as a cap and is not one: min-width still resolves
           to 260px on any screen wider than 304px, so the panel never narrowed for a phone.
           Anchored to its trigger it then hangs off the right edge -- and because these are
           hidden by opacity rather than display, a CLOSED dropdown was still widening the
           document. Measured: 70-75px of overflow on admin, archive_list, upload and
           timekeeper_uploader, which is why those four still shrank to fit. Anchored to the
           viewport instead, exactly as .task-node-popover already is above. */
        .nav-dropdown {
          position: fixed;
          left: 14px;
          right: 14px;
          top: calc(var(--tk-nav-height) + 8px);
          width: auto;
          min-width: 0;
          max-height: calc(100dvh - var(--tk-nav-height) - 24px);
          overflow-y: auto;
        }

        .nav-menu > :last-child .nav-dropdown {
          left: 14px;
          right: 14px;
        }

        .nav-dropdown-item {
          min-height: 44px;
        }

        /* Under 16px, iOS zooms the page the moment a field is focused, and does not undo it
           on blur. Measured 98 such fields across the app. */
        input,
        select,
        textarea {
          font-size: 16px;
        }

        .footer-inner {
          display: grid;
          justify-items: start;
        }

        .global-import-stat-grid,
        .global-import-detail-list div {
          grid-template-columns: 1fr;
        }

        /* ---- phone navigation sheet, ported from prod-mobile (issue #32) ----------------
           Below the breakpoint the bar cannot hold seven groups and forty actions, so the
           nav becomes a sheet behind one button. Without this the nav is still laid out at
           its desktop width -- 624px inside a 393px window -- and is simply clipped away,
           which is why beta had no reachable navigation on a phone at all.

           main's own rules above are left alone on purpose: its .task-node-popover keys off
           calc(var(--tk-nav-height) + 8px) rather than a hardcoded top, and its
           .nav-menu-trigger sizing is its own. Only selectors main did not already have are
           added here. */
/* A phone has no room for the rail the medallion sits in: 148px of reserved
           space plus a row of menus that cannot wrap is wider than the screen, so the
           last menus were pushed off it and the whole page scrolled sideways. The
           medallion shrinks to a badge that fits inside the bar, the menus wrap onto
           as many rows as they need, and the bar grows to hold them instead of
           spilling its second row over the page. */
        :root {
          --tk-header-height: 48px;
        }

        .site-nav,
        .nav-inner {
          height: auto;
          min-height: 48px;
          /* The bar sets width:100% and its own padding, so it needs border-box to stay inside
             the screen. Most pages declare a global reset, but timekeeper_uploader.html and
             demo_preparing.html do not, and there the header was 24px wider than the phone --
             the shared chrome should not depend on what each page happens to reset. */
          box-sizing: border-box;
        }


/* The bar's backdrop-filter makes it a containing block for position:fixed, which
           trapped the full-screen sheet inside a 48px header. The bar is opaque navy here, so
           the blur was buying nothing on a phone anyway. */
        .site-nav {
          backdrop-filter: none;
        }


        .nav-inner {
          flex-direction: row;
        }


        .task-node {
          width: 44px;
          height: 44px;
          padding: 3px;
        }


        .task-node-art {
          width: 38px;
          height: 38px;
          border-width: 1px;
        }


        .task-node-count {
          right: 0;
          top: 0;
          min-width: 16px;
          height: 16px;
          border-width: 1px;
          padding: 0 3px;
          font-size: 0.6rem;
        }
/* One button, one sheet. Three groups and roughly forty actions cannot be a row of
           pills on a phone: unwrapped they are wider than the screen, and wrapped they eat
           the header. A closed dropdown is also still laid out, so leaving them as floating
           panels kept widening the document even while invisible. In the sheet nothing
           floats -- each group is a section and the whole thing scrolls. */
        .nav-menu-toggle {
          display: inline-flex;
          align-items: center;
          gap: 9px;
          min-height: 44px;
          padding: 8px 14px;
          border: 1px solid var(--line);
          border-radius: 9px;
          background: var(--tk-button-bg, transparent);
          color: var(--tk-text);
          font: 850 0.82rem/1 "Source Sans Pro", "Segoe UI", sans-serif;
        }


        .nav-menu-toggle-bars,
        .nav-menu-toggle-bars::before,
        .nav-menu-toggle-bars::after {
          display: block;
          width: 17px;
          height: 2px;
          border-radius: 2px;
          background: currentColor;
        }


        .nav-menu-toggle-bars {
          position: relative;
        }


        .nav-menu-toggle-bars::before,
        .nav-menu-toggle-bars::after {
          content: "";
          position: absolute;
          left: 0;
        }


        .nav-menu-toggle-bars::before { top: -5px; }

        .nav-menu-toggle-bars::after { top: 5px; }


        .nav-menu {
          position: fixed;
          /* `inset: 0` pins all four edges, so the sheet was always exactly screen-height even
             with seven collapsed groups in it -- most of a phone screen of blank panel, and the
             page underneath completely hidden. Pin the top and the sides and leave the bottom
             free, and the sheet ends after the last group. The cap keeps an expanded group
             (Archive Tools is seventeen items) scrolling inside the sheet rather than running
             off the bottom of the screen unreachably. */
          top: 0;
          right: 0;
          left: 0;
          bottom: auto;
          max-height: 100dvh;
          z-index: 200;
          display: none;
          flex: none;
          flex-direction: column;
          /* The bar centres its children; a column sheet needs them full width instead. */
          align-items: stretch;
          margin: 0;
          padding: 0 0 env(safe-area-inset-bottom);
          background: var(--tk-bg-panel);
          /* The sheet ends after its last section, but the page behind it is the same navy, so
             nothing marked where the panel stopped -- on a phone the two read as one full-screen
             menu. An edge and a shadow make it visibly a sheet lying over the page. */
          border-bottom: 1px solid var(--line);
          box-shadow: 0 18px 32px rgba(11, 17, 32, 0.45);
          overflow-y: auto;
          /* No `overscroll-behavior: contain` here. The sheet ends after its last group and its
             content usually fits, so it has nothing to scroll itself -- containing overscroll
             meant a swipe anywhere over it did nothing at all. */
        }


        .nav-menu.sheet-open {
          display: flex;
        }


        .nav-sheet-head {
          position: sticky;
          top: 0;
          z-index: 1;
          display: flex;
          align-items: center;
          justify-content: space-between;
          gap: 12px;
          padding: 12px 16px;
          border-bottom: 1px solid var(--line);
          background: var(--tk-bg-panel);
          color: var(--tk-text);
          font-size: 1.05rem;
        }


        .nav-sheet-close {
          min-width: 44px;
          min-height: 44px;
          border: 0;
          background: transparent;
          color: var(--tk-text);
          font-size: 1.7rem;
          line-height: 1;
          cursor: pointer;
        }
/* Inside the sheet a group is a heading with its items beneath it, so nothing is
           positioned and nothing is hidden behind a second tap. */
        .nav-menu-group {
          position: static;
          width: 100%;
        }
/* These are the things you navigate to, so in the sheet they stay full-size rows that
           read as tappable. Styling them as small dim section labels buried them under the
           actions, which is the whole reason the first attempt at this failed. The .active
           variants paint parchment-on-ink for the bar and are unreadable here, so the sheet
           states its own colours rather than inheriting a state meant for another surface. */
        .nav-menu.sheet-open .nav-menu-trigger,
        .nav-menu.sheet-open .nav-menu-trigger.active,
        .nav-menu.sheet-open .nav-menu-group.open > .nav-menu-trigger {
          width: 100%;
          justify-content: space-between;
          /* Without this the trigger is content-box, so `min-height` becomes min-height PLUS
             padding plus border: 54 + 24 + 1 = 79px per row. Across nine sections that is 225px
             of screen the menu never asked for, and it pushed the sheet to 62% of an Android
             display. Stating the box model makes min-height mean what it says. */
          box-sizing: border-box;
          min-height: 54px;
          margin: 0;
          padding: 12px 16px;
          border: 0;
          border-bottom: 1px solid var(--line);
          border-radius: 0;
          background: transparent;
          box-shadow: none;
          color: var(--tk-text);
          opacity: 1;
          font-size: 1rem;
          font-weight: 850;
          letter-spacing: 0;
          text-transform: none;
          text-align: left;
        }
/* The caret is the affordance that says a row opens rather than goes somewhere. */
        .nav-menu.sheet-open .nav-caret {
          display: block;
          transition: transform 120ms ease;
        }


        .nav-menu.sheet-open .nav-menu-group.open > .nav-menu-trigger .nav-caret {
          transform: rotate(180deg);
        }
/* The open section is tinted through its heading and its items, so it reads as one
           block rather than a heading that happens to sit above some rows. */
        .nav-menu.sheet-open .nav-menu-group.open > .nav-menu-trigger {
          background: var(--tk-selected-bg, var(--tk-hover-fill));
          color: var(--tk-selected-text, var(--tk-text));
        }
/* A <button> centres its own text and an <a> does not, so the two kinds of item in
           these menus disagreed until told otherwise. */
        .nav-menu.sheet-open .nav-dropdown-item {
          justify-content: flex-start;
          min-height: 46px;
          padding: 10px 16px 10px 28px;
          border-radius: 0;
          text-align: left;
        }


        .nav-menu.sheet-open .nav-dropdown-label {
          padding: 8px 16px;
          text-align: left;
        }


        .nav-menu.sheet-open .nav-dropdown {
          position: static;
          /* Collapsed by default; the open group's rule below turns it back on. Declared here
             rather than in a later block so the two cannot fight over source order. */
          display: none;
          gap: 0;
          opacity: 1;
          pointer-events: auto;
          transform: none;
          width: auto;
          min-width: 0;
          max-height: none;
          padding: 0;
          border: 0;
          border-radius: 0;
          box-shadow: none;
          background: transparent;
        }


        .nav-menu.sheet-open .nav-menu-group.open > .nav-dropdown {
          display: grid;
          padding-bottom: 6px;
          background: var(--tk-hover-fill);
        }



        .nav-menu.sheet-open .nav-dropdown::before {
          content: none;
        }
        /* No band reserved here any more. The drawer button used to sit over the footer at
           full scroll, so the footer padded itself by 118px to clear it -- 118px of empty
           screen on every archive page, on a display that has little to spare. The button now
           steps aside when the footer comes into view instead, so the footer can be its own
           size. See .mobile-sidebar-toggle.at-footer in archive.html. */
/* A container that exists to scroll its content sideways must not be widened by that
           content. Several pages give their table a min-width so it stays readable; without
           this the container inherits that width and the page carries it. */
        .table-wrap {
          max-width: 100%;
          min-width: 0;
        }
/* Keep the press visible, but on-brand instead of the browser's blue box. */
        html {
          -webkit-tap-highlight-color: rgba(185, 130, 94, 0.28);
        }


        :focus-visible {
          outline: 2px solid var(--accent, #B9825E);
          outline-offset: 2px;
        }
      }
