/* ==========================================================================
   Crew rostering coordinator console — "the prompt book"

   Design direction, and why it is this and not a dashboard.

   The thing this replaces is a *document*: a hand-maintained year-grid workbook
   that the admin team reads fluently every day, and SPEC.md §8/§9 both make
   continuity with it an explicit requirement. So the interface is built like
   stage-management paperwork rather than like an analytics product — ruled, not
   carded; hairlines, not shadows; square corners; dense enough to read a week at
   a glance. Nothing floats.

   Two deliberate, load-bearing choices:

   1. EVERY NUMBER AND TIME IS MONOSPACED. A roster is a timing document, and
      setting times in a mono face makes them align down a column without
      tabular-figure tricks, so "8am / 8am / 1pm" reads as a column of calls
      rather than as prose. Names and prose are set in the text face.

   2. COLOUR IS NEVER THE ONLY CHANNEL. The three coverage states carry a fill
      pattern as well as a hue (solid / diagonal hatch / dense cross-hatch), a
      hover title, and a text label, so the bar survives a monochrome print, a
      colour-blind reader and a bad projector. The palette itself is drawn from
      lighting gel — moss green, straw, primary red — because that is the
      vernacular of the world this system serves, and because those three are
      already distinguishable to most kinds of colour vision.

   The accent is a theatre lavender, kept for interactive things only, so it
   never competes with the three coverage colours for meaning.

   Colour and type come from static/themes/ — see _contract.css for the token
   vocabulary this stylesheet consumes.
   ========================================================================== */

/* Layout tokens. Colour and type come from static/themes/ — see _contract.css.
   These stay here because a rail width is not a branding decision.

   Scoped to `html`, not `.shell`: accounts/templates/accounts/auth_base.html
   (sign-in, MFA, and coordinator/templates/403.html, which extends it) link
   this stylesheet but render no `.shell` element — there is no organisation
   chrome to show before someone is signed in, see auth_base.html's own
   comment — so a `.shell`-scoped --gutter left `var(--gutter)` unresolvable
   in `.messages`/`.note`'s margins on every one of those pages. An
   unresolvable var() invalidates the declaration, which falls back to 0
   rather than to anything visible. Same fix, same reasoning, as
   pwa/static/pwa/worker.css's equivalent block. */
:where(html) {
  --rail: 13.5rem;
  --gutter: 1.25rem;
  /* Phone-only minimum control height (spec §3). Same value as the worker
     app's; deliberately not a theme token (D32). */
  --tap: 48px;
}

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

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

/* Alpine's standard pre-init veil: without this, x-cloak'd conditionals flash
   visible between first paint and Alpine booting. */
[x-cloak] {
  display: none !important;
}

body {
  margin: 0;
  background: var(--ground);
  color: var(--ink);
  font: 400 13.5px/1.5 var(--face-text);
  letter-spacing: 0.005em;
}

/* Times, headcounts, dates, coverage figures. See note 1 above. */
time,
.num,
.mono,
code,
kbd,
input[type="time"],
input[type="date"],
input[type="datetime-local"] {
  font-family: var(--face-data);
  font-variant-numeric: tabular-nums;
}

a {
  color: var(--accent);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.16em;
}

a:hover {
  color: var(--accent-strong);
}

:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 2px;
  border-radius: 1px;
}

h1,
h2,
h3 {
  margin: 0;
  font-family: var(--face-display);
  /* 700, not 600: the display face is vendored at 700/800 only (see
     static/themes/_fonts.css), so a 600 request makes the browser substitute
     the 700 face anyway — declaring it is honest rather than accidental, and
     700 is what the design specifies for display type. */
  font-weight: 700;
  letter-spacing: -0.011em;
}

h1 {
  font-size: 1.35rem;
}

h2 {
  font-size: 1rem;
}

h3 {
  font-size: 0.875rem;
}

p {
  margin: 0 0 0.75rem;
  max-width: 62ch;
}

/* The uppercase tracked label is the paperwork vernacular: PHASE, CALL, CREW. */
.label {
  display: block;
  font: 600 10px/1.4 var(--face-text);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.muted {
  color: var(--ink-soft);
}

.faint {
  color: var(--ink-faint);
}

.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;
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  padding: 0.5rem 0.75rem;
  background: var(--ink);
  color: var(--ground);
}

.skip-link:focus {
  left: 0;
}

/* ==========================================================================
   Shell
   ========================================================================== */

.shell {
  display: grid;
  grid-template-columns: var(--rail) minmax(0, 1fr);
  min-height: 100vh;
}

.rail {
  border-right: 1px solid var(--rule-strong);
  background: var(--ground-sunk);
  padding: 1rem 0;
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.rail__mark {
  padding: 0 1rem 0.85rem;
  border-bottom: 1px solid var(--rule);
}

.rail__org {
  display: block;
  font-weight: 650;
  font-size: 0.9rem;
  letter-spacing: -0.01em;
}

.rail__nav {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
}

/* `.rail__more` wraps the secondary links and the footer so one id can be the
   phone's More sheet; on a desktop it is transparent to layout. `flex: 1` on
   the nav lets the footer's margin-top: auto still reach the bottom. */
.rail__more {
  display: contents;
}

.rail__link--more,
.rail__link--close {
  display: none;
}

.rail__link {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 0.5rem;
  padding: 0.42rem 1rem;
  color: var(--ink-soft);
  text-decoration: none;
  border-left: 3px solid transparent;
}

.rail__link:hover {
  background: var(--ground-raised);
  color: var(--ink);
}

.rail__link[aria-current="page"] {
  border-left-color: var(--accent);
  background: var(--ground-raised);
  color: var(--ink);
  font-weight: 600;
}

.rail__group {
  padding: 0.6rem 1rem 0.2rem;
}

.rail__foot {
  margin-top: auto;
  padding: 0.85rem 1rem 0;
  border-top: 1px solid var(--rule);
  font-size: 0.78rem;
}

.badge-count {
  font-family: var(--face-data);
  font-size: 0.7rem;
  padding: 0 0.3rem;
  border: 1px solid var(--rule-strong);
  background: var(--ground);
  color: var(--ink-soft);
}

.main {
  min-width: 0;
  display: flex;
  flex-direction: column;
}

.topbar {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--gutter);
  flex-wrap: wrap;
  padding: 1.1rem var(--gutter) 0.85rem;
  border-bottom: 1px solid var(--rule-strong);
  background: var(--ground-raised);
}

.topbar__actions {
  display: flex;
  gap: 0.4rem;
  align-items: center;
  flex-wrap: wrap;
}

.content {
  padding: var(--gutter);
  min-width: 0;
}

/* ==========================================================================
   Controls
   ========================================================================== */

.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.32rem 0.7rem;
  border: 1px solid var(--rule-strong);
  border-radius: 2px;
  background: var(--ground-raised);
  color: var(--ink);
  font: 500 12.5px/1.5 var(--face-text);
  text-decoration: none;
  cursor: pointer;
}

.btn:hover {
  background: var(--ground-sunk);
  color: var(--ink);
}

.btn--primary {
  background: var(--accent);
  border-color: var(--accent-strong);
  color: var(--on-accent);
}

.btn--primary:hover {
  background: var(--accent-strong);
  color: var(--on-accent);
}

.btn--danger {
  color: var(--stop);
  border-color: var(--stop);
}

.btn--danger:hover {
  background: var(--stop-wash);
  color: var(--stop);
}

.btn--small {
  padding: 0.16rem 0.44rem;
  font-size: 11.5px;
}

/* A row action: a one-button form that sits inline among its neighbours. */
.act {
  display: inline-block;
  vertical-align: middle;
}

.act__opt {
  white-space: nowrap;
}

.act__hours {
  width: 4.5em;
}

/* A Phase 2/3 affordance: visible, obviously inert, and labelled with the phase.
   Not hidden (§4.1 promises the action) and not wired to anything (a button that
   silently does nothing is worse than one that says it cannot yet). */
.btn[disabled],
.btn[aria-disabled="true"] {
  cursor: not-allowed;
  opacity: 0.55;
  background: repeating-linear-gradient(
    -45deg,
    var(--ground-sunk) 0 3px,
    var(--ground-raised) 3px 6px
  );
  color: var(--ink-faint);
}

.field {
  margin-bottom: 0.9rem;
  max-width: 44rem;
}

.field > label,
.field > .label {
  display: block;
  margin-bottom: 0.2rem;
  font-weight: 600;
  font-size: 12.5px;
}

.field input[type="text"],
.field input[type="email"],
.field input[type="password"],
.field input[type="number"],
.field input[type="date"],
.field input[type="time"],
.field input[type="datetime-local"],
.field select,
.field textarea {
  width: 100%;
  max-width: 26rem;
  padding: 0.34rem 0.45rem;
  border: 1px solid var(--rule-strong);
  border-radius: 2px;
  background: var(--ground-raised);
  color: var(--ink);
  font: inherit;
}

.field input[type="color"] {
  width: 3rem;
  height: 2rem;
  padding: 0;
  border: 1px solid var(--rule-strong);
  background: none;
}

.field__help {
  margin: 0.22rem 0 0;
  font-size: 11.5px;
  color: var(--ink-soft);
  max-width: 52ch;
}

.field__errors {
  margin: 0.22rem 0 0;
  padding: 0;
  list-style: none;
  font-size: 12px;
  color: var(--stop);
  font-weight: 500;
}

.field--inline {
  display: flex;
  align-items: flex-end;
  gap: 0.5rem;
  margin-bottom: 0;
}

.checks {
  display: flex;
  flex-wrap: wrap;
  gap: 0.1rem 0.85rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.checks li label,
.check-inline {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  font-weight: 400;
}

.form-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.9rem;
  align-items: flex-start;
}

.form-actions {
  display: flex;
  gap: 0.5rem;
  align-items: center;
  margin-top: 1rem;
  padding-top: 0.85rem;
  border-top: 1px solid var(--rule);
}

/* ==========================================================================
   Panels, tables, notes
   ========================================================================== */

.panel {
  border: 1px solid var(--rule-strong);
  background: var(--ground-raised);
  margin-bottom: var(--gutter);
}

.panel__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.75rem;
  flex-wrap: wrap;
  padding: 0.55rem 0.75rem;
  border-bottom: 1px solid var(--rule);
  background: var(--ground-sunk);
}

/* Only the worklist's panels fold, and only on a phone; on a desktop their
   summary is inert. A summary without --fold (the warehouse page) stays a
   real disclosure at every width. */
summary.panel__head--fold {
  list-style: none;
  pointer-events: none;
}

summary.panel__head--fold::-webkit-details-marker {
  display: none;
}

.panel__body {
  padding: 0.75rem;
}

.panel__body--flush {
  padding: 0;
}

.grid-2 {
  display: grid;
  gap: var(--gutter);
  grid-template-columns: repeat(auto-fit, minmax(19rem, 1fr));
  align-items: start;
}

.sheet {
  width: 100%;
  border-collapse: collapse;
  font-size: 12.5px;
}

.sheet th,
.sheet td {
  text-align: left;
  padding: 0.34rem 0.6rem;
  border-bottom: 1px solid var(--rule);
  vertical-align: top;
}

.sheet thead th {
  font: 600 10px/1.4 var(--face-text);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-faint);
  background: var(--ground-sunk);
  border-bottom: 1px solid var(--rule-strong);
  white-space: nowrap;
}

.sheet tbody tr:hover {
  background: var(--ground);
}

.sheet__text {
  white-space: pre-line;
  max-width: 34rem;
}

/* A table that is not redesigned for a phone still must not squash the page. */
.scroll-x {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

/* The contact card's slot row (spec §6.1). Empty until a Contact card button
   fills it; the :has() is the same one the calendar collapse relies on. */
.contact-row:not(:has(.card)) {
  display: none;
}

.sheet .contact-slot {
  padding: 0.6rem 0.75rem;
}

.note {
  border-left: 3px solid var(--rule-strong);
  padding: 0.5rem 0.75rem;
  background: var(--ground-sunk);
  font-size: 12.5px;
  margin-bottom: var(--gutter);
}

.note--warn {
  border-left-color: var(--hold);
  background: var(--hold-wash);
}

.note--stop {
  border-left-color: var(--stop);
  background: var(--stop-wash);
}

.note--later {
  border-left-color: var(--accent);
  background: var(--accent-wash);
}

/* Rendered markdown (production/venue/shift notes, via the `markdown` filter)
   emits bare `<p>`, `<ul>`, `<strong>`, `<h3>` and so on with no classes of
   its own, so `.note`'s prose has to be styled by tag rather than by BEM
   modifier. First/last child margins are collapsed so a one-paragraph note
   does not gain extra padding it never had under `linebreaksbr`. */
.note > :first-child {
  margin-top: 0;
}

.note > :last-child {
  margin-bottom: 0;
}

.note p,
.note ul,
.note ol {
  margin: 0 0 0.5rem;
}

.note ul,
.note ol {
  padding-left: 1.1rem;
}

/* markup.render_markdown demotes every heading by one level, capped at h6,
   so notes content can emit h2 through h6 but never h1 — see apply.css for
   the same reasoning applied to the job ad. */
.note h2,
.note h3,
.note h4,
.note h5,
.note h6 {
  font-size: 1em;
  font-weight: 700;
  margin: 0 0 0.35rem;
}

.note strong {
  font-weight: 700;
}

/* What a pending cancellation will do (§5.6), before it happens. Shared by
   the shift and production cancel-confirm pages. */
.plan {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

.plan__warn {
  color: var(--stop);
}

.empty {
  padding: 1.75rem 0.75rem;
  text-align: center;
  color: var(--ink-soft);
}

.messages {
  list-style: none;
  margin: 0 0 var(--gutter);
  padding: 0;
}

.messages li {
  border-left: 3px solid var(--rule-strong);
  background: var(--ground-raised);
  padding: 0.45rem 0.7rem;
  margin-bottom: 0.3rem;
  font-size: 12.5px;
}

.messages li.success {
  border-left-color: var(--go);
}

.messages li.warning {
  border-left-color: var(--hold);
  background: var(--hold-wash);
}

.messages li.error {
  border-left-color: var(--stop);
  background: var(--stop-wash);
}

.tag {
  display: inline-flex;
  align-items: center;
  gap: 0.2rem;
  padding: 0 0.32rem;
  border: 1px solid var(--rule-strong);
  border-radius: 2px;
  font: 600 10px/1.55 var(--face-text);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-soft);
  background: var(--ground);
  white-space: nowrap;
}

.tag--draft {
  border-style: dashed;
}

.tag--tentative {
  border-style: dashed;
  color: var(--hold);
  border-color: var(--hold);
}

.tag--cancelled {
  color: var(--stop);
  border-color: var(--stop);
  text-decoration: line-through;
}

.tag--covered {
  color: var(--go);
  border-color: var(--go);
}

.tag--short {
  color: var(--stop);
  border-color: var(--stop);
  background: var(--stop-wash);
}

.tag--pencilled {
  color: var(--hold);
  border-color: var(--hold);
  background: var(--hold-wash);
}

/* ==========================================================================
   THE SIGNATURE: the coverage strip (§4.1)
   Three bands, sized to real elapsed time, patterned as well as coloured.
   ========================================================================== */

.bar {
  display: flex;
  width: 100%;
  height: 1.35rem;
  border: 1px solid var(--rule-strong);
  background: var(--ground-sunk);
  overflow: hidden;
}

.bar--slim {
  height: 0.6rem;
}

.bar__seg {
  position: relative;
  min-width: 2px;
  border-right: 1px solid color-mix(in srgb, var(--ink) 28%, transparent);
}

.bar__seg:last-child {
  border-right: 0;
}

.bar__seg--covered {
  background: var(--go);
}

/* Diagonal hatch: the coordinator's intention, not a commitment (D11). Reading
   as "provisional" without relying on the hue is the whole point. */
.bar__seg--provisional {
  background: repeating-linear-gradient(
    45deg,
    var(--hold) 0 4px,
    var(--hold-wash) 4px 8px
  );
}

/* Dense cross-hatch: a real hole. Heaviest texture, because it is the thing to
   look at first. */
.bar__seg--uncovered {
  background: repeating-linear-gradient(
      45deg,
      var(--stop) 0 3px,
      transparent 3px 6px
    ),
    repeating-linear-gradient(
      -45deg,
      var(--stop) 0 3px,
      var(--stop-wash) 3px 6px
    );
}

/* The band this row is actually about, outlined in ink so it is findable inside
   a requirement whose other bands are fine. */
.bar__seg--focus {
  outline: 2px solid var(--ink);
  outline-offset: -2px;
  z-index: 1;
}

.bar__scale {
  display: flex;
  justify-content: space-between;
  font-family: var(--face-data);
  font-size: 10px;
  color: var(--ink-faint);
  margin-top: 0.12rem;
}

.bar-key {
  display: flex;
  gap: 0.85rem;
  flex-wrap: wrap;
  align-items: center;
  font-size: 11.5px;
  color: var(--ink-soft);
}

.bar-key__swatch {
  display: inline-block;
  width: 1.1rem;
  height: 0.7rem;
  border: 1px solid var(--rule-strong);
  vertical-align: -0.05rem;
  margin-right: 0.25rem;
}

/* ==========================================================================
   Gap dashboard
   ========================================================================== */

.gap {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(14rem, 22rem);
  gap: 0.75rem 1.1rem;
  padding: 0.7rem 0.75rem;
  border-bottom: 1px solid var(--rule);
  border-left: 4px solid var(--rule-strong);
}

.gap--running {
  border-left-color: var(--stop);
  background: var(--stop-wash);
}

.gap--urgent {
  border-left-color: var(--stop);
}

.gap--soon {
  border-left-color: var(--hold);
}

.gap--later {
  border-left-color: var(--rule-strong);
}

.gap__head {
  display: flex;
  gap: 0.4rem;
  align-items: baseline;
  flex-wrap: wrap;
  margin-bottom: 0.25rem;
}

.gap__when {
  font-family: var(--face-data);
  font-weight: 600;
}

.gap__proximity {
  font-family: var(--face-data);
  font-size: 11.5px;
  padding: 0 0.3rem;
  border: 1px solid currentColor;
}

.gap--running .gap__proximity,
.gap--urgent .gap__proximity {
  color: var(--stop);
  font-weight: 600;
}

.gap--soon .gap__proximity {
  color: var(--hold);
}

.gap--later .gap__proximity {
  color: var(--ink-soft);
}

.gap__reasons {
  margin: 0.4rem 0 0;
  padding: 0;
  list-style: none;
  font-size: 12px;
}

.gap__reasons li {
  border-left: 2px solid var(--hold);
  padding: 0.1rem 0 0.1rem 0.45rem;
  margin-bottom: 0.15rem;
  color: var(--ink-soft);
}

.gap__actions {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  align-items: flex-start;
}

.gap__actions-row {
  display: flex;
  gap: 0.3rem;
  flex-wrap: wrap;
}

/* ==========================================================================
   Calendar grid (§8)
   ========================================================================== */

.bands {
  border: 1px solid var(--rule-strong);
  background: var(--ground-raised);
  margin-bottom: var(--gutter);
}

.bands__row {
  display: grid;
  grid-template-columns: 13rem minmax(0, 1fr);
  gap: 0.6rem;
  align-items: center;
  padding: 0.22rem 0.6rem;
  border-bottom: 1px solid var(--rule);
}

.bands__row:last-child {
  border-bottom: 0;
}

.bands__title {
  font-size: 12.5px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.bands__track {
  position: relative;
  height: 0.85rem;
  background: var(--ground-sunk);
}

.bands__band {
  position: absolute;
  top: 0;
  bottom: 0;
  border: 1px solid color-mix(in srgb, var(--ink) 35%, transparent);
}

/* A tentative production: the whole booking is unconfirmed and offers are
   suppressed. Dashed and washed out — a different signal from the dotted
   underline a pencilled *person* gets (D11). */
.bands__band--tentative {
  border-style: dashed;
  background-image: repeating-linear-gradient(
    45deg,
    color-mix(in srgb, var(--ground-raised) 65%, transparent) 0 4px,
    transparent 4px 8px
  );
}

/* A production's own dated phases (§3.3), drawn over its band so a job that is
   booked but not yet rostered still shows where it sits. Three fills, one per
   phase: prep washed out, rehearsals hatched, shows solid. */
.bands__phase {
  position: absolute;
  top: 18%;
  bottom: 18%;
  pointer-events: auto;
  border: 1px solid color-mix(in srgb, var(--ink) 55%, transparent);
}

.bands__phase--prep {
  opacity: 0.45;
}

.bands__phase--rehearsal {
  opacity: 0.75;
  background-image: repeating-linear-gradient(
    90deg,
    color-mix(in srgb, var(--ground-raised) 70%, transparent) 0 3px,
    transparent 3px 6px
  );
}

.bands__phase--show {
  opacity: 1;
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--ground-raised) 60%, transparent);
}

/* A cancelled production: tombstoned rather than hidden by default (D19.2) —
   struck through and muted, so a coordinator can still see the job was once
   there and knows why the week is empty. */
.bands__title--cancelled {
  color: var(--ink-faint);
  text-decoration: line-through;
}

.bands__title--cancelled a {
  color: inherit;
}

.bands__band--cancelled {
  opacity: 0.6;
  background-image: repeating-linear-gradient(
    -45deg,
    color-mix(in srgb, var(--ink-faint) 45%, transparent) 0 4px,
    transparent 4px 8px
  );
}

.cal {
  width: 100%;
  border-collapse: collapse;
  table-layout: fixed;
  border: 1px solid var(--rule-strong);
  background: var(--ground-raised);
}

.cal caption {
  text-align: left;
  padding-bottom: 0.4rem;
  font-size: 11.5px;
  color: var(--ink-soft);
}

.cal thead th {
  font: 600 10px/1.6 var(--face-text);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-faint);
  background: var(--ground-sunk);
  border: 1px solid var(--rule);
  padding: 0.2rem 0.35rem;
  text-align: left;
}

.cal td {
  border: 1px solid var(--rule);
  vertical-align: top;
  padding: 0.2rem 0.28rem 0.35rem;
  height: 6.5rem;
  width: 14.28%;
}

/* Out-of-month cells are CONTENT SLOTS, not filler (§9.1, D15.5). Tinted so the
   month boundary is legible, never emptied or hidden. */
.cal td.out {
  background: var(--ground-sunk);
}

.cal td.today {
  box-shadow: inset 0 0 0 2px var(--ink);
}

.cal__day {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 0.25rem;
  margin-bottom: 0.2rem;
}

.cal__daynum {
  font-family: var(--face-data);
  font-size: 11.5px;
  font-weight: 600;
  color: var(--ink-soft);
}

.cal td.out .cal__daynum {
  color: var(--ink-faint);
  font-weight: 400;
}

.cal__gapbadge {
  font-family: var(--face-data);
  font-size: 10px;
  font-weight: 700;
  padding: 0 0.24rem;
  border: 1px solid var(--stop);
  color: var(--stop);
  background: var(--stop-wash);
}

.cal__gapbadge--soon {
  border-color: var(--hold);
  color: var(--hold);
  background: var(--hold-wash);
}

.chip {
  display: block;
  border-left: 4px solid var(--rule-strong);
  padding: 0.1rem 0.24rem 0.16rem;
  margin-bottom: 0.16rem;
  background: var(--ground);
  color: var(--ink);
  text-decoration: none;
  font-size: 11.5px;
  line-height: 1.35;
}

.chip:hover {
  background: var(--ground-sunk);
  color: var(--ink);
}

.chip--draft {
  border-left-style: dashed;
  background: repeating-linear-gradient(
    -45deg,
    var(--ground) 0 4px,
    var(--ground-sunk) 4px 8px
  );
}

.chip--cancelled {
  opacity: 0.6;
}

.chip--cancelled .chip__title {
  text-decoration: line-through;
}

.chip__time {
  font-family: var(--face-data);
  font-size: 10.5px;
  color: var(--ink-soft);
  display: block;
}

.chip__title {
  font-weight: 600;
  display: block;
}

.chip__crew {
  display: block;
  color: var(--ink-soft);
  font-size: 10.5px;
}

/* A pencilled person: `Name?`, dotted underline. Deliberately NOT the same
   signal as a tentative production (D11) — same mark, different attachment, and
   each carries its own hover text. */
.pencilled {
  text-decoration: underline dotted var(--hold);
  text-underline-offset: 0.14em;
  color: var(--hold);
}

.cal__note {
  display: block;
  font-size: 10.5px;
  color: var(--ink-soft);
  border-top: 1px dotted var(--rule-strong);
  padding-top: 0.1rem;
  margin-top: 0.16rem;
}

/* ==========================================================================
   Skills matrix
   ========================================================================== */

.matrix {
  border-collapse: collapse;
  font-size: 12px;
}

.matrix th,
.matrix td {
  border: 1px solid var(--rule);
  padding: 0.22rem 0.35rem;
}

.matrix thead th {
  background: var(--ground-sunk);
  font: 600 10px/1.4 var(--face-text);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-faint);
  writing-mode: vertical-rl;
  text-orientation: mixed;
  height: 6.5rem;
}

.matrix thead th.matrix__corner {
  writing-mode: horizontal-tb;
  height: auto;
  text-align: left;
}

.matrix tbody th {
  text-align: left;
  font-weight: 500;
  white-space: nowrap;
  background: var(--ground-raised);
}

.cell {
  text-align: center;
  font-family: var(--face-data);
  font-size: 10.5px;
}

.cell--none {
  color: var(--ink-faint);
}

.cell--held,
.cell--current {
  background: var(--go-wash);
  color: var(--go);
}

.cell--expiring {
  background: var(--hold-wash);
  color: var(--hold);
  font-weight: 700;
}

.cell--expired {
  background: var(--stop-wash);
  color: var(--stop);
  font-weight: 700;
}

/* Edit mode: the cell is the checkbox's hit area, not just the 16px box. */
.cell--edit {
  padding: 0;
}

.cell--edit input {
  width: 100%;
  min-height: 26px;
  margin: 0;
  cursor: pointer;
  accent-color: var(--go);
}

/* ==========================================================================
   Contact card (§4.1, §6.5) — the one thing allowed to float, because it is a
   card somebody picks up.
   ========================================================================== */

.card {
  border: 1px solid var(--ink);
  background: var(--ground-raised);
  box-shadow: 3px 3px 0 var(--rule-strong);
  padding: 0.75rem;
  max-width: 22rem;
}

.card__name {
  font-size: 1.05rem;
  font-weight: 650;
  margin-bottom: 0.1rem;
}

.card__number {
  display: block;
  font-family: var(--face-data);
  font-size: 1.15rem;
  letter-spacing: 0.01em;
  margin: 0.35rem 0;
}

.card__actions {
  display: flex;
  gap: 0.35rem;
  flex-wrap: wrap;
  margin: 0.5rem 0;
}

/* ==========================================================================
   Auth pages
   ========================================================================== */

.auth {
  min-height: 100vh;
  display: grid;
  place-items: center;
  padding: 2rem 1rem;
}

.auth__sheet {
  width: 100%;
  max-width: 26rem;
  border: 1px solid var(--rule-strong);
  background: var(--ground-raised);
}

.auth__head {
  padding: 1rem 1.25rem 0.85rem;
  border-bottom: 1px solid var(--rule-strong);
  background: var(--ground-sunk);
}

.auth__body {
  padding: 1.1rem 1.25rem 1.25rem;
}

.auth__steps {
  display: flex;
  gap: 0.35rem;
  align-items: center;
  font: 600 10px/1.4 var(--face-text);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin-bottom: 0.4rem;
}

.auth__step--on {
  color: var(--accent);
}

.qr {
  display: grid;
  place-items: center;
  padding: 0.75rem;
  background: var(--ground-raised);
  border: 1px solid var(--rule-strong);
  margin: 0 auto 0.75rem;
  max-width: 15rem;
}

.qr svg {
  width: 100%;
  height: auto;
  display: block;
}

.codes {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(7rem, 1fr));
  gap: 0.3rem;
  margin: 0.75rem 0;
  padding: 0;
  list-style: none;
}

.codes li {
  font-family: var(--face-data);
  font-size: 0.95rem;
  letter-spacing: 0.06em;
  padding: 0.28rem 0.4rem;
  border: 1px solid var(--rule-strong);
  background: var(--ground);
  text-align: center;
}

.secret {
  font-family: var(--face-data);
  font-size: 11px;
  word-break: break-all;
  color: var(--ink-soft);
}

/* ==========================================================================
   Responsive. A coordinator's phone is a real target: they work gaps while
   walking a venue.
   ========================================================================== */

@media (max-width: 60rem) {
  .gap {
    grid-template-columns: minmax(0, 1fr);
  }

  .cal td {
    height: auto;
    min-height: 4rem;
  }
}

/* Tablets: the rail stacks full width above the page, as it did before the
   phone bottom bar existed. Only below 44rem does the rail become the bottom
   bar. */
@media (min-width: 44.0625rem) and (max-width: 60rem) {
  .shell {
    grid-template-columns: 1fr;
  }

  .rail {
    border-right: 0;
    border-bottom: 1px solid var(--rule-strong);
  }

  .rail__nav {
    flex-direction: row;
    flex-wrap: wrap;
  }

  .rail__group,
  .rail__foot {
    width: 100%;
  }
}

@media (max-width: 44rem) {
  /* --- Shell: the rail is a bottom tab bar, the rest is behind More ------- */

  body {
    font-size: 16px;
  }

  /* Room for the bottom bar. On .shell, not on body: the sign-in and refused
     pages carry no rail and must not gain dead scroll. */
  .shell {
    grid-template-columns: 1fr;
    padding-bottom: calc(3.5rem + env(safe-area-inset-bottom, 0px));
  }

  .rail {
    position: fixed;
    inset: auto 0 0 0;
    z-index: 9;
    flex-direction: row;
    gap: 0;
    padding: 0 0 env(safe-area-inset-bottom, 0px);
    border-right: 0;
    border-top: 1px solid var(--rule-strong);
  }

  .rail__mark {
    display: none;
  }

  .rail__nav {
    flex-direction: row;
    width: 100%;
  }

  .rail__nav > .rail__link {
    flex: 1;
    justify-content: center;
    align-items: center;
    min-height: 3.25rem;
    padding: 0.375rem 0.25rem;
    border-left: 0;
    font-size: 0.8rem;
    font-weight: 600;
  }

  .rail__nav > .rail__link[aria-current="page"] {
    box-shadow: inset 0 3px 0 var(--accent);
  }

  .rail__link--more {
    display: flex;
  }

  /* The More sheet. Hidden until it is the URL target; then a fixed panel
     above the bar. Close is a link to #main, so no script is involved. */
  .rail__more {
    display: none;
  }

  .rail__more:target {
    display: flex;
    flex-direction: column;
    position: fixed;
    inset: 0 0 calc(3.25rem + env(safe-area-inset-bottom, 0px)) 0;
    z-index: 10;
    overflow-y: auto;
    padding: 0.5rem 0 1rem;
    background: var(--ground-sunk);
  }

  .rail__more .rail__link {
    min-height: var(--tap);
    align-items: center;
    padding: 0.5rem 1rem;
    font-size: 1rem;
  }

  .rail__link--close {
    display: flex;
    justify-content: flex-end;
    color: var(--ink);
  }

  .rail__foot {
    margin-top: 1rem;
  }

  /* --- Topbar stacks ------------------------------------------------------- */

  .topbar {
    flex-direction: column;
    align-items: stretch;
    gap: 0.6rem;
  }

  /* --- Controls grow to a thumb ------------------------------------------ */

  .btn,
  button,
  summary.btn,
  .field input:not([type="checkbox"]):not([type="radio"]):not([type="color"]),
  .field select,
  .field textarea,
  input[type="datetime-local"],
  input[type="number"],
  input[type="text"],
  select {
    min-height: var(--tap);
    font-size: 15px;
  }

  .btn--small {
    padding: 0.32rem 0.7rem;
  }

  .field input,
  .field select,
  .field textarea {
    max-width: none;
  }

  .form-actions {
    flex-wrap: wrap;
  }

  .form-actions .btn--primary {
    flex: 1 1 100%;
    justify-content: center;
  }

  .sheet {
    font-size: 15px;
  }

  /* Touch has no hover; give a tap something to show. */
  .sheet tbody tr:active {
    background: var(--ground);
  }

  /* --- Card tables (spec §5.1). Opt-in: `.sheet--cards` -------------------- */

  .sheet--cards,
  .sheet--cards tbody,
  .sheet--cards tr,
  .sheet--cards td {
    display: block;
    width: auto;
  }

  .sheet--cards thead {
    display: none;
  }

  /* The tail gap belongs to the tbody: on the last row it would land on the
     hidden contact-row instead. */
  .sheet--cards tbody {
    padding-bottom: 0.6rem;
  }

  .sheet--cards tbody tr {
    margin: 0.6rem 0.6rem 0;
    padding: 0.35rem 0 0.5rem;
    border: 1px solid var(--rule-strong);
    background: var(--ground-raised);
  }

  .sheet--cards td {
    padding: 0.25rem 0.75rem;
    border-bottom: 0;
  }

  .sheet--cards td[data-label]:not([data-label=""])::before {
    content: attr(data-label);
    display: block;
    font: 600 10px/1.4 var(--face-text);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--ink-faint);
  }

  /* The card's title line: the person or the thing. No label above it. */
  .sheet--cards td.sheet__title::before {
    display: none;
  }

  .sheet--cards td.sheet__title {
    font-size: 1.05rem;
    font-weight: 600;
  }

  /* Long free text: wraps at full width. */
  .sheet--cards td.sheet__text {
    white-space: pre-line;
    max-width: none;
  }

  /* Action cells: no label, buttons wrap as a row at tap height. */
  .sheet--cards td:not([data-label]),
  .sheet--cards td[data-label=""] {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    align-items: flex-start;
    padding-top: 0.5rem;
  }

  .sheet--cards th[scope="rowgroup"] {
    display: block;
    padding: 0.6rem 0.75rem 0;
    border-bottom: 0;
  }

  .sheet--cards .contact-row {
    margin-top: -0.6rem;
    border-top: 0;
  }

  /* --- Foldable panels: the summary is tappable on a phone ----------------- */

  summary.panel__head--fold {
    pointer-events: auto;
    cursor: pointer;
    min-height: var(--tap);
    align-items: center;
  }

  summary.panel__head--fold::after {
    content: "▾";
    margin-left: auto;
    color: var(--ink-faint);
  }

  details.panel:not([open]) > summary.panel__head--fold::after {
    content: "▸";
  }

  .act {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    align-items: center;
    width: 100%;
  }

  .act__opt {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    min-height: var(--tap);
  }

  .act__hours {
    width: 5.5em;
  }

  .act--details > form {
    width: 100%;
  }

  /* Keep the existing calendar collapse rules below this line, unchanged. */

  /* The month grid stops being a grid and becomes a list of days with work.
     Seven 2.5rem columns is not a calendar, it is a smear. */
  .cal,
  .cal caption,
  .cal tbody,
  .cal tr,
  .cal td {
    display: block;
    width: auto;
  }

  .cal thead {
    display: none;
  }

  /* Only days with work survive the collapse: an empty cell in a list is a blank
     line, and thirty of them is not a calendar either. */
  .cal td:not(:has(.chip)):not(:has(.cal__note)) {
    display: none;
  }

  .cal td {
    border-top: 0;
  }

  /* The weekday header is gone, so the day number alone loses its bearings. */
  .cal__weekday {
    display: inline;
  }
}

/* Shown only in the collapsed mobile list, where the column header is gone. */
.cal__weekday {
  display: none;
  font-family: var(--face-data);
  font-size: 11px;
  color: var(--ink-faint);
}

@media print {
  .rail,
  .topbar__actions,
  .gap__actions,
  .skip-link {
    display: none;
  }

  .shell {
    grid-template-columns: 1fr;
  }

  body {
    background: var(--ground-raised);
  }
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}

/* A standby call (§3.3): might not go ahead. Flagged wherever a draft is, in the
   hold colour — it is real to crew, unlike a draft, but not a certainty. */
.tag--standby {
  border-color: var(--hold);
  color: var(--hold);
}
