/* ============================================================================
   Base: the reset, document defaults, focus, scrollbars and the handful of
   utilities every surface composes from. No component lives here.

   This file is a sibling of packages/design/base.css rather than a copy of it.
   That file is the chat product's base and carries its chrome in the print
   block and its container-query name on #app; importing it would drag a
   composer and a space rail into a stylesheet that has neither. What was worth
   keeping - the focus discipline, the scrollbar treatment, the text utilities -
   is kept, and the differences are commented where they are not obvious.

   Nothing in here names a colour or a pixel spacing. Both come from tokens.css.
   ========================================================================= */

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

html, body {
  margin: 0;
  padding: 0;
  height: 100%;
  background: var(--c-bg);
  color: var(--c-text);
  font-family: var(--t-font);
  font-size: var(--t-base);
  line-height: var(--t-body);
  letter-spacing: var(--t-track-normal);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  overscroll-behavior: none;
}

/* An app shell, not a document. The page itself never scrolls; the nav and the
   main column each scroll on their own, so a long roster cannot drag the top
   bar off screen and a wide sheet cannot slide the whole layout sideways.

   This also means the horizontal-overflow check in scripts/audit-geometry.mjs
   would be trivially satisfied by the document, which is why that script does
   not stop at the document: it walks every element and flags anything whose
   content is wider than its box while its own overflow-x is visible or hidden.
   Overflow that is clipped is still overflow. */
body {
  position: fixed;
  inset: 0;
  overflow: hidden;
  -webkit-tap-highlight-color: transparent;
}

h1, h2, h3, h4, h5, h6 {
  margin: 0;
  font-family: var(--t-display);
  font-weight: var(--t-semibold);
  line-height: var(--t-tight);
  letter-spacing: var(--t-track-display);
}
p { margin: 0; }
ul, ol { margin: 0; padding: 0; list-style: none; }
img, svg, video, canvas { display: block; max-width: 100%; }
/* LINK INK IS NOT THE ACCENT, and the difference matters in five of the ten
   theme blocks. --c-accent is designed as a FILL that carries --c-accent-text
   on top of it, so in every dark look it is a LIGHT hue - a light purple, a
   bright red - and using it as ink on a dark surface measures around 3.9:1.
   That is a real AA failure on every link in the app at night, and the geometry
   audit found ten of them.

   Mixing the accent towards --c-text is the fix, and it is self-correcting:
   --c-text is near-black in a light look, so the mix darkens the link there,
   and near-white in a dark look, so the same declaration lightens it there. One
   line, ten blocks, no new token, measured from 3.9:1 to 5.4:1 and above
   everywhere it was failing. */
a { color: color-mix(in srgb, var(--c-accent) 72%, var(--c-text)); text-decoration: none; }
a:hover { text-decoration: underline; }
table { border-collapse: collapse; border-spacing: 0; }

/* Code sits inside whatever surrounds it and a monospace face draws visibly
   larger at the same nominal size, so this wants a ratio against its context
   rather than a rung on the scale. */
code, pre, kbd, samp { font-family: var(--t-mono); font-size: 0.9em; }

kbd {
  display: inline-block;
  min-width: 1.6em;
  padding: 1px 5px;
  border: var(--bw) solid var(--c-border-strong);
  border-bottom-width: 2px;
  border-radius: var(--r-xs);
  background: var(--c-surface-2);
  color: var(--c-text-2);
  font-size: var(--t-xs);
  font-family: var(--t-font);
  font-weight: var(--t-semibold);
  text-align: center;
  line-height: 1.5;
}

/* ------------------------------------------------------------------ numerals
   Every number in Arc sits in a column that is read against the column above
   and below it: a score, a budget in minutes, a rank, a day count. Proportional
   figures make those columns ragged and make a changing value jitter in place.
   tabular-nums is therefore not a flourish here, it is what makes the tables
   legible, and it is applied by role rather than globally so running prose
   keeps the face's real figures. */
.num, .sheet td, .sheet th, .lb-rank, .stat-value, time, .mono {
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}
.mono { font-family: var(--t-mono); }

/* ------------------------------------------------------------------ focus
   Visible for keyboard users, invisible for a mouse click. Arc is a
   keyboard-first surface, so this ring is load-bearing: it is the only thing
   telling somebody driving the time sheet with arrow keys where they are. */
:focus { outline: none; }
:focus-visible {
  outline: 2px solid var(--c-accent);
  outline-offset: 2px;
  border-radius: var(--r-xs);
}

/* A heading the router moved focus to on a screen change. The move itself is
   right - a keyboard user must land in the content rather than be left on the
   nav item they clicked while the page changes underneath them - but the ring
   is not: the person did not navigate to the heading, the heading came to them,
   and a 2px accent box drawn around every page title on every load reads as a
   rendering fault. The screen change is its own feedback. Anything a person
   actually tabs to keeps its ring, because this only matches the -1 targets. */
h1[tabindex="-1"]:focus-visible,
h1[tabindex="-1"]:focus { outline: none; }

/* The sign-in screen replaces the shell rather than living inside it, so for
   that one state #app stops being a two column grid. Without this the auth
   panel is laid into a grid row sized by its own content while asking for
   height 100% of that row, and the circularity resolves a few pixels short -
   which showed up as a hairline of page background above the aubergine. */
#app[data-chrome="none"] { display: block; }

/* The skip link is the first thing in the tab order and is invisible until it
   has focus. Without it a keyboard user tabs through the whole nav on every
   screen change to reach the content. */
.skip-link {
  position: fixed;
  top: var(--s-4);
  left: var(--s-4);
  z-index: var(--z-toast);
  padding: var(--s-4) var(--s-6);
  border-radius: var(--r-md);
  background: var(--c-accent);
  color: var(--c-accent-text);
  font-weight: var(--t-semibold);
  box-shadow: var(--e-3);
  transform: translateY(-200%);
  transition: transform var(--m-base) var(--m-out);
}
.skip-link:focus-visible { transform: none; text-decoration: none; }

::selection { background: var(--c-accent); color: var(--c-accent-text); }

/* ------------------------------------------------------------------ scrollbars
   Thin, and only inked once the pane is hovered, so a resting screen is calm
   and a screen you are working in tells you how far down the list you are. */
* { scrollbar-width: thin; scrollbar-color: transparent transparent; }
*:hover { scrollbar-color: var(--c-border-strong) transparent; }
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: transparent;
  border: 3px solid transparent;
  border-radius: var(--r-full);
  background-clip: content-box;
}
*:hover::-webkit-scrollbar-thumb { background: var(--c-border-strong); background-clip: content-box; }
::-webkit-scrollbar-thumb:hover { background: var(--c-text-3); background-clip: content-box; }
::-webkit-scrollbar-corner { background: transparent; }

/* ------------------------------------------------------------------ shell root */
#app {
  height: 100%;
  display: grid;
  grid-template-columns: var(--sidebar-w) minmax(0, 1fr);
  /* minmax(0, 1fr) rather than 1fr, and this is the single most important
     declaration in the layout. A grid track sized 1fr has an automatic minimum
     of min-content, so one un-wrappable thing inside the main column - a wide
     table, a long unbroken id, the time sheet - silently widens the track past
     the viewport and pushes the nav off screen. The zero minimum makes the
     track respect the viewport and forces the overflow down into whichever
     child actually owns a scroll container. */
  overflow: hidden;
  background: var(--c-bg);
}

/* ------------------------------------------------------------------ utilities */
.hidden { display: none !important; }
.sp { flex: 1 1 auto; }

.muted { color: var(--c-text-2); }
.faint { color: var(--c-text-3); }
.tiny { font-size: var(--t-xs); }
.small { font-size: var(--t-sm); }
.strong { font-weight: var(--t-semibold); }
.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.nowrap { white-space: nowrap; }
.clamp-2 {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* The tracked uppercase label that heads a group, a table section or a card.
   Set from --t-track-caps so a look can retune all of them together: editorial
   wants them wide and quiet, precision wants them tight and machined. */
.eyebrow {
  font-size: var(--t-2xs);
  font-weight: var(--t-semibold);
  letter-spacing: var(--t-track-caps);
  text-transform: uppercase;
  color: var(--c-text-3);
}

.row { display: flex; align-items: center; }
.row.gap { gap: var(--s-4); }
.col { display: flex; flex-direction: column; }
.col.gap { gap: var(--s-4); }
.wrap { flex-wrap: wrap; }

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

/* ------------------------------------------------------------------ scroll-x
   The single escape hatch from "no horizontal page scroll". A table, the time
   sheet and a wide chart are allowed to be wider than the window, and each one
   gets its own scroller so the page itself never moves.

   The gradient hints are a real usability fix rather than decoration: a table
   that continues past the right edge with no visual cue reads as a table that
   ends there, and people do not go looking for the column they cannot see. The
   masks are painted by a scroll listener setting data-edge, because a
   pure-CSS version needs scroll-driven animations that are not everywhere yet. */
.scroll-x {
  overflow-x: auto;
  overflow-y: hidden;
  max-width: 100%;
  overscroll-behavior-x: contain;
  -webkit-overflow-scrolling: touch;
}
.scroll-x-wrap { position: relative; min-width: 0; }
.scroll-x-wrap::before,
.scroll-x-wrap::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  width: var(--s-9);
  pointer-events: none;
  opacity: 0;
  transition: opacity var(--m-base) var(--m-ease);
  z-index: 2;
}
.scroll-x-wrap::before {
  left: 0;
  background: linear-gradient(to right, var(--c-bg), transparent);
}
.scroll-x-wrap::after {
  right: 0;
  background: linear-gradient(to left, var(--c-bg), transparent);
}
.scroll-x-wrap[data-edge~="start"]::before { opacity: 1; }
.scroll-x-wrap[data-edge~="end"]::after { opacity: 1; }

/* On a narrow screen the scroller is the rule rather than the exception, and
   the fade alone is a weak cue against a light ground: it is the same colour as
   the surface it fades into. So below this width the thumb is inked at rest
   instead of on hover, which is the one unambiguous signal that there is more
   table to the right. Hover does not exist on the devices this applies to
   anyway, which is why the default rule cannot help here. */
@media (max-width: 700px) {
  .scroll-x-wrap .scroll-x { scrollbar-color: var(--c-border-strong) transparent; }
  .scroll-x-wrap .scroll-x::-webkit-scrollbar-thumb {
    background: var(--c-border-strong);
    background-clip: content-box;
  }
}

/* ------------------------------------------------------------------ boot
   What the first paint shows while the modules resolve. It is centred in the
   whole grid rather than in a column because at that moment there is no
   column: the shell has not been built yet. */
.boot {
  grid-column: 1 / -1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--s-5);
  color: var(--c-text-3);
}
.boot-mark { color: var(--c-accent); animation: boot-pulse 1.4s var(--m-ease) infinite; }
.boot-word {
  font-family: var(--t-display);
  font-size: var(--t-sm);
  font-weight: var(--t-semibold);
  letter-spacing: var(--t-track-caps);
  text-transform: uppercase;
}
@keyframes boot-pulse {
  0%, 100% { opacity: 0.35; }
  50%      { opacity: 1; }
}

/* ------------------------------------------------------------------ print
   People print a roster and a cycle score sheet. Drop the chrome and let the
   content run. */
@media print {
  #nav, #topbar, #toasts, #overlays, .skip-link { display: none !important; }
  body { position: static; overflow: visible; }
  #app { display: block; height: auto; }
  #main, #screen { overflow: visible; height: auto; }
}
