/* page-next-8-hours.css: Plant Toolbox next-8-hours (wrapper #p-shift).
   Generated by .plans/site-overhaul/tools/port.py from ptb-site-overhaul-src/css/p-shift.css.
   Production state: P1 light ("Light steel") only, review flags and mockup chrome removed. Loaded after site.css. */

/* ==== p-shift.css ==== */
/* ==========================================================================
   p-shift.css · inner page "Next 8 hours" (#p-shift). Every selector starts with #p-shift (COMPONENTS.md).
   n8 redesign, 2026-10-28 ("One Shift on Line 4", .plans/site-overhaul/2026-10-27-n8-redesign/n8-spec.md): the page
   follows one shift on Line 4. Owner reorder 2026-10-29: the handover now comes before the huddle and SMART before
   the sources; the partials run in this order (content/views/next-8-hours/):
   01-header (#ps-top: the copy beside the Line Remote Display, #ps-display, the wall screen drawn as the hero) ·
   02-handover, 05:15 (#ps-handover: "Manage the handover from one crew to the next.", the Shift Handover card) · 03-huddle, 05:45 (#ps-huddle, kept: the 05:00–14:00
   playhead over a day on the Line Action Plan; next-8-hours.js plays it as the visitor scrolls) · 04-smart (#pa-top,
   kept: the SMART rail beside #4182; next-8-hours.js) · 05-sources (#pa-sources, kept) ·
   08-cta (#ps-next: the site's closing band, the page's last block; the #ps-status rows beside it were parked 2026-10-28).
   04-smart and 05-sources came from /action-planning (2026-10-26) and keep its pa- names. The blocks below kept their
   numbers and their cascade order through the reorder.
   Blocks, in cascade order: Shared bits · 1 header · 1a item atoms (the page's one item grammar: type tag, person,
   now chip, flags, .ps-tight; values mirror site.css §50) · 6 huddle ·
   7 handover · 7a sources · 7b SMART · 8 closing band (a note, no rules) · the tail forced-colors block (the huddle's marks).
   §3 (role lens), §5 (on the wall) and §9 (CTA row) retired on 2026-10-28 with 04-lens, 06-floor and 09-next, and §2
   (the shift, #ps-engine: row zero over the shared run sheet; it repeated home's #ne-next-eight) on 2026-10-29 with
   03-engine, and §4 (Now 09:40, #ps-dash/#ps-floor) on 2026-10-29 with 05-dash (§1's "Today on Line 4" card went
   with it, as 01-today-card), all parked in content/views/next-8-hours/.parking-lot/ with each block as a sibling
   .css; the numbers are kept, so no block was renumbered. Each redesigned block carries its own forced-colors rules. The huddle and #pa-top draw product
   frames with the shared .app parts (site.css §49). No rule uses a sibling combinator across sections.
   ========================================================================== */

/* Shared bits ---------------------------------------------------------------- */
/* D36 height (QA2-04): this long page takes the 96px step of the section rhythm (64/96/120) from 1100, where the site
   default is 120. Only the inner .sec sections use --section-pad; the header keeps its own 96/64. */
@media (min-width: 1100px) {
  #p-shift { --section-pad: 96px; }
}

/* 1. Page header (#ps-top, #ps-display) ----------------------------------------------------------------------------
   The copy (eyebrow, H1, lead) beside the Line Remote Display in the right column (.ps-head-visual): figure#ps-display
   (.ps-wd), the shared line board in its current look (site.css §49s-sky) inside the drawn wall TV (§49s-tv),
   recreated from content/img/screens/ops-3-line-display.jpg (owner 2026-10-29). The "Today on Line 4" card that sat
   here was parked that day (.parking-lot/01-today-card.*). This block holds only layout and motion: the header grid
   (5/7 from 1100; one column below, 1024-1099 undoing the site's 7/5), the figure's head row with Pause / Play at its
   right, the lower panels' rotation (from a 520px screen each slot's own data-state picks its panel, dt or ap on the
   left and ck or sf on the right, so the two swap on different beats; below, the split's data-state picks the one
   panel shown) and the transitions next-8-hours.js plays through, one lane at a time, which run only with motion
   allowed (under reduced motion Play cuts). */
@media (min-width: 1024px) and (max-width: 1099px) {
  #p-shift .ps-head-grid { grid-template-columns: minmax(0, 1fr); gap: 0; }
  #p-shift .ps-head-grid > .page-header-copy { display: contents; }
  #p-shift .ps-head-visual { order: 1; margin-top: var(--s-6); }
}
@media (min-width: 1100px) {
  #p-shift .ps-head-grid { grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); gap: var(--s-7); align-items: start; }
  #p-shift .ps-head-visual { align-self: start; }
}
#p-shift .ps-wd { max-width: 720px; margin: 0; }
@media (min-width: 1100px) {
  #p-shift .ps-wd { max-width: none; }
}
#p-shift .ps-wd-head { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 8px; max-width: none; margin: 0 0 12px; font-size: 14px; font-weight: 600; line-height: 1.4; color: var(--ink-2); }
#p-shift .ps-wd-head > .icon { flex: none; width: 16px; height: 16px; color: var(--ink-3); }
#p-shift .ps-wd-head > #ps-wd-name { flex: 1 1 14em; min-width: 0; }
#p-shift .ps-wd-head > .ps-wd-play { margin-left: auto; }
/* Pause / Play: the look of home's .hf-btn (home.css); the glyph follows data-state (playing | paused). */
#p-shift .ps-wd-play { display: inline-flex; flex: none; align-items: center; gap: 6px; min-height: 32px; padding: 4px 12px 4px 10px; font: 600 13px/1.5 var(--font-sans); color: var(--teal-ink); background: var(--surface); border: 1px solid var(--hairline); border-radius: var(--r-control); cursor: pointer; }
#p-shift .ps-wd-play[hidden] { display: none; }
#p-shift .ps-wd-play:hover { border-color: var(--teal-ink); }
#p-shift .ps-wd-play .icon { width: 12px; height: 12px; }
#p-shift .ps-wd-play[data-state=paused] .ps-wd-i-pause,
#p-shift .ps-wd-play:not([data-state=paused]) .ps-wd-i-play { display: none; }
@media (max-width: 719px) {
  #p-shift .ps-wd-play { min-height: 40px; }
}
/* The rotation: every panel shares its slot's one cell, so a swap never changes the screen's height. */
#p-shift .ps-wd-slot { display: grid; min-width: 0; min-height: 0; }
#p-shift .ps-wd-slot > [data-panel] { grid-area: 1 / 1; opacity: 0; visibility: hidden; }
@container (width >= 520px) {
  #p-shift .ps-wd-slot[data-state=dt] > [data-panel=dt],
  #p-shift .ps-wd-slot[data-state=ap] > [data-panel=ap],
  #p-shift .ps-wd-slot[data-state=ck] > [data-panel=ck],
  #p-shift .ps-wd-slot[data-state=sf] > [data-panel=sf] { opacity: 1; visibility: visible; transform: none; transition-delay: 0s; }
}
@container (width < 520px) {
  #p-shift .ps-wd-split > .ps-wd-slot { grid-area: 1 / 1; }
  #p-shift .ps-wd-split[data-state=dt] [data-panel=dt],
  #p-shift .ps-wd-split[data-state=ap] [data-panel=ap],
  #p-shift .ps-wd-split[data-state=ck] [data-panel=ck],
  #p-shift .ps-wd-split[data-state=sf] [data-panel=sf] { opacity: 1; visibility: visible; transform: none; transition-delay: 0s; }
}
/* Motion: bars grow and change colour, panels cross-fade, a new row eases in. */
@media (prefers-reduced-motion: no-preference) {
  #p-shift .ps-wd .app-board-bars > span { transition: height .6s cubic-bezier(.22, .61, .36, 1), background-color .3s ease; }
  #p-shift .ps-wd-slot > [data-panel] { transform: translateY(4px); transition: opacity .4s ease, transform .4s ease, visibility 0s linear .4s; }
  #p-shift .ps-wd .app-board-ev:not([data-state=off]) { animation: ps-wd-in .4s ease both; }
}
@keyframes ps-wd-in {
  from { opacity: 0; transform: translateY(3px); }
}

/* 1a. Item atoms (n8-spec §3) -------------------------------------------------------------------------------------
   One item grammar for every redesigned section of this page: the job type (colour, always with the tag word and
   its icon), the person (initials avatar, name, role), the static Now chip, the
   status flags and the tighter section rhythm. The values mirror site.css §50's .ne-tag, .ne-av, .ne-name and
   .ne-role (home.css 30-next-eight until §50 lands) and must change together. They are page-own classes under
   #p-shift, so no §50 layout rule (grid areas, the 1023px change) reaches them; never use .run-sheet outside the
   console the renderer emits. */
#p-shift .ps-ty--production  { --ps-mark: var(--app-type-d); --ps-tint: var(--ok-tint);      --ps-ink: var(--ok-ink); }
#p-shift .ps-ty--changeover  { --ps-mark: var(--app-type-c); --ps-tint: var(--warn-tint);    --ps-ink: var(--warn-ink); }
#p-shift .ps-ty--maintenance { --ps-mark: var(--app-type-i); --ps-tint: var(--app-s30-bg);   --ps-ink: var(--app-s30-ink); }
#p-shift .ps-ty--quality     { --ps-mark: var(--app-type-q); --ps-tint: var(--app-s20-bg);   --ps-ink: var(--app-s20-ink); }
#p-shift .ps-ty--safety      { --ps-mark: var(--app-type-s); --ps-tint: var(--app-bad-soft); --ps-ink: var(--app-bad-ink); }
#p-shift .ps-ty--leader      { --ps-mark: var(--app-type-p); --ps-tint: var(--app-s5-bg);    --ps-ink: var(--app-s5-ink); }
/* The Shift Event: a system job, neutral. */
#p-shift .ps-ty--shift       { --ps-mark: var(--ink-3);      --ps-tint: var(--app-s50-bg);   --ps-ink: var(--app-s50-ink); }

/* Type tag: the icon and the word on the type's tint; the type comes from its own .ps-ty--* or an ancestor's. */
#p-shift .ps-tag {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 1px 7px 1px 6px;
  background: var(--ps-tint, var(--app-s50-bg));
  border-radius: var(--r-control);
  font-size: 12px;
  font-weight: 600;
  line-height: 18px;
  color: var(--ps-ink, var(--app-s50-ink));
  white-space: nowrap;
}
#p-shift .ps-tag .icon { width: 13px; height: 13px; flex: none; color: var(--ps-mark, var(--ink-3)); }

/* Person: the avatar (always aria-hidden) beside the name over the role. --sm 24px; --sys holds an
   icon (a system, not a person); .ps-avs overlaps a crew; .ps-who--line is one line, "(av) Name · Role". */
#p-shift .ps-who { display: grid; grid-template-columns: 30px minmax(0, 1fr); grid-template-areas: "av name" "av role"; column-gap: 10px; align-items: center; min-width: 0; }
#p-shift .ps-who > :is(.ps-av, .ps-avs) { grid-area: av; justify-self: center; }
#p-shift .ps-who:has(> .ps-avs) { grid-template-columns: auto minmax(0, 1fr); }
#p-shift .ps-who-name { grid-area: name; align-self: end; min-width: 0; font-size: 14px; font-weight: 600; line-height: 1.3; color: var(--ink); }
#p-shift .ps-who-role { grid-area: role; align-self: start; min-width: 0; font-size: 13px; line-height: 1.35; color: var(--ink-3); }
#p-shift .ps-av {
  display: inline-grid;
  place-items: center;
  flex: none;
  width: 30px;
  height: 30px;
  background: var(--app-avatar);
  border: 1px solid var(--app-avatar-line);
  border-radius: 50%;
  font-size: 12px;
  font-weight: 700;
  line-height: 1;
  color: var(--app-primary);
}
#p-shift .ps-av--sm { width: 24px; height: 24px; font-size: 10px; }
#p-shift .ps-av--sys { background: var(--surface); border-color: var(--hairline); color: var(--ink-2); }
#p-shift .ps-av--sys .icon { width: 16px; height: 16px; }
#p-shift .ps-avs { display: inline-flex; align-items: center; }
#p-shift .ps-avs .ps-av + .ps-av { margin-left: -4px; box-shadow: 0 0 0 2px var(--surface); }
#p-shift .ps-who--line { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 0 6px; }
#p-shift .ps-who--line .ps-av { width: 22px; height: 22px; font-size: 10px; }
#p-shift .ps-who--line :is(.ps-who-name, .ps-who-role) { align-self: center; font-size: 13px; line-height: 18px; }
#p-shift .ps-who--line .ps-who-role::before { content: "· " / ""; }

/* Now chip: the .hz-now-chip look, but static (site.css positions .hz-now-chip absolutely; never reuse it). */
#p-shift .ps-now-chip {
  display: inline-block;
  padding: 1px 6px;
  background: var(--teal);
  border: 1px solid var(--teal);
  border-radius: 3px;
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  line-height: 1.4;
  color: var(--white);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* Status flags: the word always shows; the tone and the icon only repeat it. */
#p-shift .ps-flag {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 1px 7px;
  background: var(--app-s50-bg);
  border: 1px solid var(--hairline);
  border-radius: var(--r-control);
  font-size: 12px;
  font-weight: 600;
  line-height: 18px;
  color: var(--app-s50-ink);
  white-space: nowrap;
}
#p-shift .ps-flag .icon { width: 12px; height: 12px; flex: none; }
#p-shift :is(.ps-flag--off, .ps-flag--late) { background: var(--danger-tint); border-color: var(--danger-border); color: var(--danger-ink); }
#p-shift .ps-flag--soon { background: var(--warn-tint); border-color: var(--warn-border); color: var(--warn-ink); }
#p-shift .ps-flag--idle { background: var(--app-s50-bg); border-color: var(--hairline); color: var(--app-s50-ink); }

/* Section rhythm: redesigned sections take 64px from 768 (the kept ones stay at the page's 96 from 1100). */
@media (min-width: 768px) {
  #p-shift .ps-tight { --section-pad: 64px; }
}

@media (forced-colors: active) {
  #p-shift :is(.ps-tag, .ps-av, .ps-flag, .ps-now-chip) { border: 1px solid; }
  #p-shift :is(.ps-tag, .ps-flag, .ps-av) .icon { color: currentColor; }
  #p-shift :is(.ps-tag, .ps-who, .ps-flag) a { color: LinkText; }
}

/* 6. Pre-shift huddle -------------------------------------------------------- */
/* Owner brief 2026-10-26: no split. The copy, the link and the moment note (.ps-huddle-notes, a polite live region
   that follows the playhead) on top, then the look-ahead and the board at the full container width.
   Owner 2026-10-27: on wider screens the scroll drives the playhead, with the figure pinned (.is-scrolly, see
   "Scroll mode" after the entrance rules); phones, short screens and reduced motion keep the autoplay. */
#p-shift .ps-huddle-stack > .section-head { margin-bottom: var(--s-6); }
#p-shift .ps-huddle-stack > .section-head .link-ghost { justify-self: start; }
#p-shift .ps-huddle-notes { max-width: 52rem; }
/* Look-ahead timeline: 04:00-15:00 in half-hour columns, and the time control. The playhead (.ps-look-mark) sits at
   --m = (minutes - 240) / 660, 05:45 by default; next-8-hours.js sets --m on .ps-look as the range moves. */
#p-shift .ps-look {
  --lw: 112px;
  --m: 0.1591;
  position: relative;
  display: grid;
  gap: 8px;
  margin-bottom: var(--s-4);
  padding: var(--s-3) var(--s-4) var(--s-4);
  background: var(--bg-subtle);
  border: 1px solid var(--hairline);
  border-radius: var(--r-card);
}
/* Top row: the day, the drag hint and Replay (both hidden until next-8-hours.js runs). Replay is the site's small
   secondary button. */
#p-shift .ps-look-top { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 4px var(--s-3); min-height: 32px; }
#p-shift .ps-look-cap { font-size: 13px; line-height: 1.4; color: var(--ink-3); }
#p-shift .ps-look-cap b { font-weight: 600; color: var(--ink-2); }
#p-shift .ps-h-replay { flex: none; min-height: 32px; padding: 4px 12px; font: 600 13px/1.5 var(--font-sans); color: var(--teal-ink); background: var(--surface); border: 1px solid var(--hairline); border-radius: var(--r-control); cursor: pointer; }
#p-shift .ps-h-replay:hover { border-color: var(--teal-ink); }
#p-shift .ps-h-replay[hidden] { display: none; }
@media (max-width: 767px) { #p-shift .ps-h-replay { min-height: 40px; } }
/* The axis box holds the ruler, the two rows, the range and the playhead; it has no padding, so 100% is the axis. */
#p-shift .ps-look-axis { --thumb: 20px; position: relative; display: grid; gap: 6px; min-width: 0; }
#p-shift .ps-look-ruler { display: grid; grid-template-columns: repeat(11, minmax(0, 1fr)); margin-left: var(--lw); }
#p-shift .ps-look-ruler li { min-width: 0; padding-left: 4px; border-left: 1px solid var(--hairline); font-family: var(--font-mono); font-size: var(--fs-mono); line-height: 1.6; color: var(--ink-3); }
#p-shift .ps-look-row { display: grid; grid-template-columns: var(--lw) minmax(0, 1fr); align-items: center; }
#p-shift .ps-look-k { position: relative; z-index: 2; justify-self: start; padding-right: 6px; background: var(--bg-subtle); font-size: 13px; font-weight: 600; line-height: 1.4; color: var(--ink-2); }
#p-shift .ps-look-track { display: grid; grid-template-columns: repeat(22, minmax(0, 1fr)); min-width: 0; }
#p-shift .ps-look-bar {
  grid-column: var(--c) / span var(--n);
  min-width: 0;
  margin: 0 1px;
  padding: 4px 8px;
  overflow: hidden;
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: 3px;
  font-size: 13px;
  line-height: 1.3;
  white-space: nowrap;
  text-overflow: ellipsis;
  color: var(--ink-2);
}
#p-shift .ps-look-bar { position: relative; z-index: 2; }
#p-shift .ps-lb--a { color: var(--ink); }
#p-shift .ps-lb--board { background: var(--tint); border-color: var(--tint-border); color: var(--ink); }
/* The playhead: a line behind the bars (they stay readable) with a knob on the ruler as its handle. No transition:
   next-8-hours.js moves it every frame while it plays. */
#p-shift .ps-look-mark {
  position: absolute;
  top: -4px;
  bottom: -6px;
  left: calc(var(--lw) + (100% - var(--lw)) * var(--m));
  z-index: 1;
  width: 2px;
  margin-left: -1px;
  background: var(--teal);
  pointer-events: none;
}
#p-shift .ps-look-mark::before { content: ""; position: absolute; top: -3px; left: 50%; width: 14px; height: 14px; margin-left: -7px; border-radius: 50%; background: var(--teal); box-shadow: 0 0 0 2px var(--bg-subtle); }
/* The range: a real input over the 05:00-14:00 stretch of the axis, transparent, so the playhead is what shows. Its
   thumb is --thumb wide in both engines and the input is that much wider than the stretch, so the thumb's centre
   sits on the playhead for every value. Keyboard focus rings the knob. Disabled (no JS) it is inert. */
#p-shift .ps-look-range {
  position: absolute;
  top: -8px;
  bottom: -8px;
  left: calc(var(--lw) + (100% - var(--lw)) / 11 - var(--thumb) / 2);
  z-index: 5;
  width: calc((100% - var(--lw)) * 9 / 11 + var(--thumb));
  height: auto;
  margin: 0;
  padding: 0;
  background: transparent;
  opacity: 0;
  cursor: ew-resize;
  touch-action: pan-y;
  -webkit-appearance: none;
  appearance: none;
}
#p-shift .ps-look-range:disabled { cursor: default; }
#p-shift .ps-look-range::-webkit-slider-runnable-track { height: 100%; background: transparent; border: 0; }
#p-shift .ps-look-range::-webkit-slider-thumb { width: var(--thumb); height: 100%; border: 0; -webkit-appearance: none; appearance: none; }
#p-shift .ps-look-range::-moz-range-track { height: 100%; background: transparent; border: 0; }
#p-shift .ps-look-range::-moz-range-thumb { width: var(--thumb); height: 100%; border: 0; border-radius: 0; }
#p-shift .ps-look-range:focus-visible + .ps-look-mark::before { outline: 2px solid var(--focus); outline-offset: 2px; }
@media (max-width: 599px) {
  #p-shift .ps-look { --lw: 0px; }
  #p-shift .ps-look-row { grid-template-columns: minmax(0, 1fr); gap: 4px; }
  #p-shift .ps-look-bar { padding-inline: 4px; text-align: center; }
  #p-shift .ps-wide { display: none; }
}
/* Below 1100 the two-hour Shift B bar is too short for "Shift B"; it reads "B". */
@media (max-width: 1099px) { #p-shift .ps-lb--b .ps-wide { display: none; } }
/* Board frame (Line Action Plan D32): an .app frame with the PT mark in the strip and the board's clock in the title
   row (the huddle's clock shows the playhead's time, set by next-8-hours.js). */
#p-shift .ps-lap { min-width: 0; margin: 0; }
#p-shift .ps-board-clock { flex: none; margin: 0; font-size: 22px; font-weight: 700; line-height: 1.2; color: var(--app-ink); font-variant-numeric: tabular-nums; }

/* Owner brief 2026-10-26 (second pass): the huddle is a day on the Line Action Plan. The timeline contract (see
   03-huddle.php): next-8-hours.js puts .is-off on [data-from]/[data-until] elements outside their window and sets
   data-state on [data-states] elements; the server renders 05:45. Off keeps its slot (visibility), and a value that
   changes sits in a .ps-swap (its variants stacked in one cell), so neither the board nor a row changes size. */
#p-shift .ps-huddle :is(.is-off, [data-state~="off"]) { visibility: hidden; }
#p-shift .ps-swap { display: inline-grid; vertical-align: middle; }
#p-shift .ps-swap > * { grid-area: 1 / 1; }
/* The line under the timeline: what happens at the playhead (the range's aria-valuetext says the same). */
#p-shift .ps-look-now { max-width: none; font-size: 14px; line-height: 1.45; color: var(--ink-2); }
#p-shift .ps-look-now .mono { margin-right: 8px; color: var(--teal-ink); }

/* The strip: plant and line, the Take Action | Comments switch (hidden under 600, .app-bar-wide), the Illustrative tag. */
#p-shift .ps-lap-loc { display: grid; flex: 0 1 auto; min-width: 0; overflow: hidden; font-size: var(--app-fs-sm); line-height: 1.25; color: var(--app-hdr-ink); white-space: nowrap; text-overflow: ellipsis; }
#p-shift .ps-lap-loc b { color: var(--app-primary-dark); }
#p-shift .ps-lap-mode { flex: none; min-height: 32px; margin-inline: auto; border-color: var(--app-primary); }
#p-shift .ps-lap-mode > span { gap: 6px; padding: 0 12px; }
#p-shift .ps-lap-mode > .is-on { background: var(--app-primary); color: var(--app-card); box-shadow: none; }
#p-shift .ps-lap-mode .app-i { width: 13px; height: 13px; }
@container app-bar (max-width: 599px) { #p-shift .ps-lap-mode { display: none; } }
#p-shift .ps-lap .app-body { position: relative; }
/* Page head: the title and its filters (level, date, shift), the links under them; the clock and the line TV's
   barometer at the right. */
#p-shift .ps-lap-head { display: flex; flex-wrap: wrap; align-items: flex-start; justify-content: space-between; gap: 12px 24px; min-width: 0; }
#p-shift .ps-lap-head > :first-child { min-width: 0; }
#p-shift .ps-lap-title { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
#p-shift .ps-lap-title .app-h1 { margin-right: 8px; }
#p-shift .ps-lap-title .app-select { flex: none; max-width: 100%; }
#p-shift .ps-lap-links { display: flex; flex-wrap: wrap; gap: 4px 20px; margin-top: 8px; font-size: var(--app-fs-sm); font-weight: 700; color: var(--app-primary); }
#p-shift .ps-lap-side { display: grid; justify-items: end; gap: 6px; }
#p-shift .ps-lrd { display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: 6px; max-width: none; }
#p-shift .ps-lrd-k { font-size: var(--app-fs-xs); font-weight: 700; color: var(--app-mute); }
#p-shift .ps-lrd .app-chip b { margin-right: 4px; }
#p-shift .ps-chip-good { background: var(--app-good-soft); border-color: var(--app-good-soft); color: var(--app-good-ink); }
#p-shift .ps-chip-good b { color: var(--app-good-ink); }
@container app-body (max-width: 559px) {
  #p-shift :is(.ps-lap-side, .ps-lrd) { justify-items: start; justify-content: flex-start; }
}

/* Body: the Score Card rings in a column at the left (a row above the table under 720), then the table and the
   three cards. A ring is one segment a day of the month: --segs (a conic gradient from 03-huddle.php) under thin
   gaps in the frame's background, masked to a donut; Cost carries two KPIs, so a second ring sits inside. */
#p-shift .ps-lap-grid { position: relative; display: grid; gap: 16px; min-width: 0; }
#p-shift .ps-rings { display: flex; justify-content: space-between; gap: 6px; margin: 0; padding: 0; list-style: none; }
#p-shift .ps-lr { --lr: 52px; display: grid; place-items: center; width: var(--lr); aspect-ratio: 1; }
#p-shift .ps-lr > * { grid-area: 1 / 1; }
#p-shift .ps-lr-ring {
  --w: 40%;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  background: repeating-conic-gradient(var(--app-bg) 0 1.5deg, transparent 0 calc(360deg / 31)), var(--segs);
  -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - var(--w)), #000 calc(100% - var(--w) + .5px));
  mask: radial-gradient(farthest-side, transparent calc(100% - var(--w)), #000 calc(100% - var(--w) + .5px));
}
#p-shift .ps-lr--two .ps-lr-ring { --w: 22%; }
#p-shift .ps-lr--two .ps-lr-ring--in { --w: 30%; width: 74%; height: 74%; }
#p-shift .ps-lr > b { font-size: 15px; font-weight: 400; line-height: 1; color: var(--app-ink-2); }
@container app-body (min-width: 720px) {
  #p-shift .ps-lap-grid { grid-template-columns: 88px minmax(0, 1fr); align-items: start; }
  #p-shift .ps-rings { flex-direction: column; justify-content: flex-start; gap: 14px; padding-top: 4px; }
  #p-shift .ps-lr { --lr: 84px; }
  #p-shift .ps-lr > b { font-size: 24px; }
}
#p-shift .ps-lap-work { container: ps-lapw / inline-size; display: grid; gap: 12px; min-width: 0; }
#p-shift .ps-lap-tcard { container: ps-lapt / inline-size; }
#p-shift .ps-lap-tbar { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px 12px; padding: 10px 12px 8px 14px; border-bottom: 1px solid var(--app-line); }
#p-shift .ps-lap-tbar .app-summary b { font-size: 18px; }
#p-shift .ps-btn-soft { background: var(--app-primary-soft); border-color: var(--app-primary-line); }
#p-shift .ps-btn-grey { background: var(--app-fill); border-color: var(--app-line); color: var(--app-ink-2); }
#p-shift .ps-btn-on { background: var(--app-primary-soft); border-color: var(--app-primary); }
#p-shift :is(.ps-btn-soft, .ps-btn-on) .app-i { width: 14px; height: 14px; }

/* The action table: the product's columns (grip, star, Type, Area, Status, Problem Statement, Action Description,
   Owner, Due Date; the comment count sits after the id). The highlighted row is the product's yellow; a done row fades
   to mute. Under 960 the grip and Area go, under 780 the star and the problem (it joins the action's sub-line), and
   under 600 each row stacks: the type chip, the action, then status, owner and due wrapping under it. */
#p-shift .ps-lap-t th { padding: 8px; background: var(--app-foot); }
#p-shift .ps-lap-t td { padding: 9px 8px; line-height: 1.35; color: var(--app-ink); }
#p-shift .ps-lap-t :is(.ps-c-grip, .ps-c-star) { width: 1%; padding-inline: 8px 2px; }
#p-shift .ps-lap-t :is(.ps-c-type, .ps-c-area, .ps-c-st, .ps-c-own, .ps-c-due) { white-space: nowrap; }
#p-shift .ps-lap-t :is(.ps-c-area, .ps-c-prob) { color: var(--app-ink-2); }
#p-shift .ps-c-prob { min-width: 9em; }
#p-shift .ps-c-act { min-width: 11em; }
#p-shift .ps-c-act b { display: block; color: var(--app-ink); }
#p-shift .ps-act-sub { display: block; margin-top: 2px; font-size: var(--app-fs-xs); color: var(--app-mute); }
#p-shift .ps-act-prob { display: none; }
#p-shift .ps-act-msgs { margin-left: 8px; vertical-align: baseline; }
#p-shift .ps-act-msgs .app-i { width: 13px; height: 13px; margin-right: 3px; }
#p-shift .ps-lap-t .app-who { font-size: var(--app-fs-data); }
#p-shift .ps-lap-t .app-av { width: 22px; height: 22px; font-size: 10px; }
#p-shift .ps-owner-none { display: inline-flex; align-items: center; min-height: 24px; padding: 0 9px; border: 1px dashed var(--app-owner-line); border-radius: var(--app-r-round); font-size: var(--app-fs-xs); color: var(--app-mute); }
#p-shift .ps-grip { display: inline-block; width: 8px; height: 13px; background: radial-gradient(circle, var(--app-faint) 1.1px, transparent 1.5px) 0 0 / 4px 4.4px; vertical-align: middle; }
#p-shift .ps-star { display: inline-block; width: 15px; height: 15px; background: var(--app-line); clip-path: polygon(50% 0, 61% 35%, 98% 35%, 68% 57%, 79% 91%, 50% 70%, 21% 91%, 32% 57%, 2% 35%, 39% 35%); vertical-align: middle; }
#p-shift .ps-star.is-on { background: var(--app-bolt); }
#p-shift .ps-tr { transition: background-color .4s ease; }
#p-shift .ps-tr[data-state~="hl"] { background: var(--app-bolt-soft); }
#p-shift .ps-tr[data-state~="done"] :is(.ps-c-act b, .ps-c-prob) { color: var(--app-mute); }
#p-shift .ps-tr[data-state~="done"] .ps-c-due .app-pill { background: var(--app-s5-bg); color: var(--app-mute); }
@container ps-lapt (max-width: 959px) { #p-shift .ps-lap-t :is(.ps-c-grip, .ps-c-area) { display: none; } }
@container ps-lapt (max-width: 779px) {
  #p-shift .ps-lap-t :is(.ps-c-star, .ps-c-prob) { display: none; }
  #p-shift .ps-act-prob { display: inline; }
}
@container ps-lapt (max-width: 599px) {
  #p-shift .ps-lap-t thead { display: none; }
  #p-shift :is(.ps-lap-t, .ps-lap-t tbody) { display: block; }
  #p-shift .ps-tr { position: relative; display: flex; flex-wrap: wrap; align-items: center; gap: 6px 8px; padding: 10px 12px 10px 40px; border-bottom: 1px solid var(--app-line-2); }
  #p-shift .ps-tr:last-child { border-bottom: 0; }
  #p-shift .ps-lap-t .ps-tr > td { display: block; padding: 0; border: 0; }
  #p-shift .ps-lap-t .ps-tr > :is(.ps-c-grip, .ps-c-star, .ps-c-area, .ps-c-prob) { display: none; }
  #p-shift .ps-lap-t .ps-tr > .ps-c-type { position: absolute; top: 11px; left: 12px; }
  #p-shift .ps-tr > .ps-c-act { flex: 1 0 100%; }
  #p-shift .ps-type-w { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
}
/* The three cards: Information & Visitors, New Problems & Irritants, Successes, each with its add row; side by side
   from 640 of the work column. */
#p-shift .ps-lap-cards { display: grid; gap: 12px; }
@container ps-lapw (min-width: 640px) { #p-shift .ps-lap-cards { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
#p-shift .ps-lc-h { display: flex; align-items: center; gap: 8px; padding: 10px 12px 4px; }
#p-shift .ps-lc-h .app-card-t { flex: 1; min-width: 0; font-size: var(--app-fs-md); }
#p-shift .ps-lc-ic { flex: none; width: 14px; height: 14px; border: 1.5px solid var(--app-ink-2); border-radius: 50%; }
#p-shift .ps-lc-h .app-i { width: 16px; height: 16px; color: var(--app-mute); transform: rotate(90deg); }
#p-shift .ps-lc-add { display: flex; align-items: center; justify-content: space-between; margin: 4px 12px 0; padding: 6px 2px; border-bottom: 1px solid var(--app-line); font-size: var(--app-fs-sm); color: var(--app-mute); }
#p-shift .ps-lc-add .app-i { width: 14px; height: 14px; color: var(--app-good); }
#p-shift .ps-lc-list { margin: 0; padding: 2px 12px 8px; list-style: none; }
#p-shift .ps-lc-list > li { display: grid; grid-template-columns: 8px minmax(0, 1fr); align-items: center; gap: 10px; padding: 7px 2px; border-bottom: 1px solid var(--app-line-2); font-size: var(--app-fs-sm); line-height: 1.4; color: var(--app-ink); }
#p-shift .ps-lc-list > li:last-child { border-bottom: 0; }
#p-shift .ps-lc-list .app-pill { margin-left: 4px; }
/* Phone trim (owner 2026-10-29): on screens under 768 (the script's phone board, autoplay, never pinned) the board
   drops the rows and cards 03-huddle.php flags .ps-no-phone (#4158, #4190, Information & Visitors, New Problems &
   Irritants), keeping four rows and Successes alone, so the stack is shorter. display: none, so they take no room and
   are not read; the lone card spans the grid (the work column can pass 640 by 698). The lines that named a dropped
   card swap to their .ps-phone-only wording. Tablet, desktop and print show it all, without the phone wording. */
@media screen and (max-width: 767px) {
  #p-shift .ps-huddle .ps-no-phone { display: none; }
  #p-shift .ps-lap-cards { grid-template-columns: minmax(0, 1fr); }
}
@media print, screen and (min-width: 768px) {
  #p-shift .ps-huddle .ps-phone-only { display: none; }
}

/* The readiness popup, laid out like the product's KPI popup (title and the KPI's period, Previous / Next / Close,
   a KPI card, then the detail): the decision KPI card (status dot, name, score box, the trigger strip with the bolt)
   and the bounded meter, beside the Decision Tree's five questions. data-state on .ps-pop-kpi is the tone letter and
   the score (n, r25, r50, y70, g85): the dot, the strip and the meter follow it. It covers the rings, the table and
   the cards with a scrim (the page head stays in view); it fades and settles in, and out at shift start. */
#p-shift .ps-scrim { position: absolute; inset: -6px; z-index: 3; border-radius: var(--app-r); background: rgba(20, 32, 56, .28); transition: opacity .35s ease, visibility .35s; }
#p-shift .ps-pop {
  position: absolute;
  top: 0;
  right: 0;
  left: 0;
  z-index: 4;
  display: grid;
  gap: 14px;
  padding: 16px 18px 18px;
  background: var(--app-card);
  border: 1px solid var(--app-line);
  border-radius: var(--app-r-dlg);
  box-shadow: var(--app-shadow-lg);
  transition: opacity .35s ease, transform .35s ease, visibility .35s;
}
#p-shift :is(.ps-pop, .ps-scrim)[data-state="off"] { opacity: 0; }
#p-shift .ps-pop[data-state="off"] { transform: translateY(12px) scale(.985); }
#p-shift .ps-pop-h { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px 16px; }
#p-shift .ps-pop-t { font-size: 22px; font-weight: 400; line-height: 1.25; color: var(--app-ink); }
#p-shift .ps-pop-t small { font-size: var(--app-fs-md); color: var(--app-ink-2); }
#p-shift .ps-pop-b { display: grid; gap: 8px 28px; min-width: 0; }
@container app-body (min-width: 860px) { #p-shift .ps-pop-b { grid-template-columns: minmax(0, 340px) minmax(0, 1fr); align-items: start; } }
@container app-body (max-width: 559px) { #p-shift .ps-pop { padding: 14px; } }
#p-shift .ps-pop-kpi { --kc: var(--app-faint); --kc-strip: var(--app-mute); --v: 0; display: grid; }
#p-shift .ps-pop-kpi[data-state^="r"] { --kc: var(--app-bad); --kc-strip: var(--app-bad-ink); }
#p-shift .ps-pop-kpi[data-state^="y"] { --kc: var(--app-warn); --kc-strip: var(--app-warn-ink); }
#p-shift .ps-pop-kpi[data-state^="g"] { --kc: var(--app-good); --kc-strip: var(--app-good-ink); }
#p-shift .ps-pop-kpi[data-state$="25"] { --v: .25; }
#p-shift .ps-pop-kpi[data-state$="50"] { --v: .5; }
#p-shift .ps-pop-kpi[data-state$="70"] { --v: .7; }
#p-shift .ps-pop-kpi[data-state$="85"] { --v: .85; }
#p-shift .ps-kc { overflow: hidden; background: var(--app-foot); border: 1px solid var(--app-line); border-radius: var(--app-r); box-shadow: var(--app-shadow); }
#p-shift .ps-kc-top { display: grid; grid-template-columns: 10px minmax(0, 1fr) auto; align-items: center; gap: 10px; padding: 14px 14px 14px 16px; }
#p-shift .ps-kc-dot { width: 9px; height: 9px; border-radius: 50%; background: var(--kc); transition: background-color .3s ease; }
#p-shift .ps-kc-nm { font-size: var(--app-fs-title); font-weight: 700; line-height: 1.3; color: var(--app-ink); }
#p-shift .ps-kc-nm small { display: block; font-size: var(--app-fs-xs); font-weight: 400; color: var(--app-mute); }
#p-shift .ps-kc-val { display: grid; justify-items: center; min-width: 96px; padding: 6px 10px; border-radius: var(--app-r-ctl); background: var(--app-badge); }
#p-shift .ps-kc-num { font-size: 22px; font-weight: 700; line-height: 1.1; color: var(--app-ink); font-variant-numeric: tabular-nums; }
#p-shift .ps-kc-word { justify-items: center; font-size: var(--app-fs-xs); font-weight: 700; color: var(--kc-strip); }
#p-shift .ps-kc-strip { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; gap: 10px; padding: 8px 14px; background: var(--kc-strip); color: var(--app-card); font-size: var(--app-fs-xs); font-weight: 700; transition: background-color .3s ease; }
#p-shift .ps-kc-strip .ps-swap { justify-self: center; }
#p-shift .ps-kc-strip .app-i { width: 14px; height: 14px; }
#p-shift .ps-kc-meter { --meter-w: 100%; }
#p-shift .ps-kc-meter > .meter-fill { width: calc(var(--v) * 100%); background: var(--kc); transition: width .45s ease, background-color .3s ease; }
#p-shift .ps-pop .meter-bound { font-family: var(--app-font); font-size: var(--app-fs-xs); letter-spacing: 0; color: var(--app-ink-2); }
/* Decision Tree: each question with its rule as a pill (red-tinted when it forces Red) and the answer as the product's
   radio dots in the primary blue; open, the dots are dashed and empty. The question and its pills share one line
   where it fits (.ps-q-text is a wrapping flex row). */
#p-shift .ps-dtree-head { display: grid; grid-template-columns: minmax(0, 1fr) 36px 36px; gap: 8px; padding-bottom: 6px; border-bottom: 1px solid var(--app-line); font-size: var(--app-fs-xs); font-weight: 700; color: var(--app-mute); text-align: center; }
#p-shift .ps-dtree-head > :first-child { text-align: left; }
#p-shift .ps-dtree-list { margin: 0; padding: 0; list-style: none; }
#p-shift .ps-q { display: grid; grid-template-columns: 26px minmax(0, 1fr) 36px 36px; align-items: center; gap: 8px; padding-block: 6px; border-bottom: 1px solid var(--app-line-2); }
#p-shift .ps-q-n { font-size: var(--app-fs-xs); font-weight: 700; color: var(--app-mute); }
#p-shift .ps-q-text { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 10px; max-width: none; font-size: var(--app-fs-sm); line-height: 1.4; color: var(--app-ink); }
#p-shift .ps-q-rule { display: flex; flex-wrap: wrap; gap: 4px; }
#p-shift .ps-pill-red { background: var(--app-bad-soft); color: var(--app-bad-ink); }
#p-shift :is(.ps-q-yes, .ps-q-no) { justify-self: center; width: 18px; height: 18px; background: var(--app-card); border: 1.5px dashed var(--app-field-line); border-radius: 50%; transition: background-color .25s ease, border-color .25s ease; }
#p-shift .ps-q:is([data-state="y"], [data-state="n"]) :is(.ps-q-yes, .ps-q-no) { border-style: solid; }
#p-shift .ps-q[data-state="y"] .ps-q-yes,
#p-shift .ps-q[data-state="n"] .ps-q-no { background: var(--app-primary); border-color: var(--app-primary); box-shadow: inset 0 0 0 3px var(--app-card); }
#p-shift .ps-q-ans { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
#p-shift .ps-pop-note { margin-top: 10px; font-size: var(--app-fs-sm); line-height: 1.45; color: var(--app-ink-2); }
#p-shift .ps-pop-note b { color: var(--app-good-ink); }
@container app-body (max-width: 559px) {
  #p-shift .ps-dtree-head { grid-template-columns: minmax(0, 1fr) 28px 28px; gap: 6px; }
  #p-shift .ps-q { grid-template-columns: 22px minmax(0, 1fr) 28px 28px; gap: 6px; }
}

/* The detail drawer (the product's slide-out: the action, its problem, chips, Create RCA / Escalate / Change Level,
   the comment thread, Comment | Action and the composer) slides in from the right over the board; under 560 it
   covers the board's width from the top. A draft shows in the composer, then posts to the thread. */
#p-shift .ps-drw { position: absolute; top: 0; right: 0; bottom: 0; z-index: 5; width: min(400px, 100%); margin: 0; border-width: 0 0 0 1px; border-radius: 0; box-shadow: var(--app-shadow-lg); transition: transform .45s cubic-bezier(.3, .7, .4, 1), visibility .45s; }
#p-shift .ps-drw[data-state="off"] { transform: translateX(105%); }
#p-shift .ps-drw .app-drawer-t { margin-top: 0; }
#p-shift .ps-drw .app-drawer-path { font-size: var(--app-fs-sm); }
#p-shift .ps-drw-x { color: var(--app-bad); }
#p-shift .ps-drw .app-drawer-b { flex: 1; grid-template-rows: auto auto 1fr; }
#p-shift .ps-drw-thread { display: grid; align-content: end; gap: 12px; padding-top: 12px; border-top: 1px solid var(--app-line-2); }
#p-shift .ps-drw .app-msg small b { margin-right: 4px; color: var(--app-ink); }
#p-shift .ps-drw-f { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: end; gap: 8px; }
#p-shift .ps-drw-f .app-seg { grid-column: 1 / -1; justify-self: start; min-height: 30px; }
#p-shift .ps-drw-in { min-height: 64px; font-size: var(--app-fs-sm); line-height: 1.45; }
#p-shift .ps-drw-ph { color: var(--app-mute); }
#p-shift .ps-send { background: var(--app-navy); border-color: var(--app-navy); color: var(--app-card); }
#p-shift .ps-draft::after { content: ""; display: inline-block; width: 1.5px; height: 1.05em; margin-left: 1px; background: var(--app-primary); vertical-align: -2px; }
@container app-body (max-width: 559px) { #p-shift .ps-drw { bottom: auto; width: 100%; border-width: 0 0 1px; } }

/* Entrance: a new row, item, comment or cell value fades in, an answered question flashes, the draft's caret blinks.
   Only once next-8-hours.js runs (.is-live), never under reduced motion. */
@media (prefers-reduced-motion: no-preference) {
  #p-shift .ps-huddle.is-live .ps-tr[data-state~="new"] { animation: ps-row-in .7s ease-out both; }
  #p-shift .ps-huddle.is-live :is(.ps-lap-t .ps-swap, .ps-lc-list .dd-stack, .ps-drw-thread, .ps-lap-tbar .ps-swap) > :not(.is-off),
  #p-shift .ps-huddle.is-live .ps-lc-list > li:not(.is-off) { animation: ps-in .5s ease-out both; }
  #p-shift .ps-huddle.is-live .ps-q:is([data-state="y"], [data-state="n"]) { animation: ps-q-in .9s ease-out; }
  #p-shift .ps-huddle.is-live .ps-draft::after { animation: ps-caret 1s steps(1) infinite; }
}
@keyframes ps-in { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }
@keyframes ps-row-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes ps-q-in { from { background: var(--app-bolt-soft); } to { background: transparent; } }
@keyframes ps-caret { 50% { opacity: 0; } }

/* Scroll mode (owner 2026-10-27, the port of home's .s-tiers; next-8-hours.js adds .is-scrolly and sets the custom
   properties). The stack's second row is the track, --hd-track-h tall (the figure plus the run), and the figure sticks
   at --hd-pin-top at its top (start, never stretched). While pinned the look-ahead is compacted (the day and Replay
   row goes: the date is in the board's filter and the range's name, and scrolling up is the replay) and the board's
   links and strip tighten; the drawn board alone is zoomed to the room left (--hd-zoom), so the timeline, the
   now-line and the caption stay full size (the caption hangs below a tight figure, below). Print gets the plain
   stack back. */
#p-shift .ps-huddle.is-scrolly .ps-huddle-stack { display: grid; grid-template-columns: minmax(0, 1fr); grid-template-rows: auto var(--hd-track-h, auto); }
#p-shift .ps-huddle.is-scrolly .ps-huddle-fig { position: sticky; top: var(--hd-pin-top, 72px); align-self: start; min-width: 0; }
#p-shift .ps-huddle.is-scrolly .ps-look-top { display: none; }
#p-shift .ps-huddle.is-scrolly .ps-look { gap: 6px; margin-bottom: 8px; padding: 8px 12px 10px; }
#p-shift .ps-huddle.is-scrolly .ps-lap-links { display: none; }
#p-shift .ps-huddle.is-scrolly .ps-lap .app-bar { min-height: 40px; }
#p-shift .ps-huddle.is-scrolly .ps-lap-app { zoom: var(--hd-zoom, 1); }
/* Tight (.is-tight: the figure would need zoom): the caption leaves the pinned figure and hangs just below it, in
   --hd-cap-h kept clear under the stack, so the board gets its room (about 0.07 more zoom) and the caption reads as
   the figure unpins. The board's own Illustrative · concept tag stays in view while it plays. */
#p-shift .ps-huddle.is-scrolly.is-tight .ps-huddle-stack { margin-bottom: var(--hd-cap-h, 0px); }
#p-shift .ps-huddle.is-scrolly.is-tight .ps-lap > figcaption { position: absolute; top: 100%; left: 0; right: 0; }
@media print {
  #p-shift .ps-huddle.is-scrolly .ps-huddle-stack { grid-template-rows: auto auto; }
  #p-shift .ps-huddle.is-scrolly .ps-huddle-fig { position: static; }
  #p-shift .ps-huddle.is-scrolly.is-tight .ps-huddle-stack { margin-bottom: 0; }
  #p-shift .ps-huddle.is-scrolly.is-tight .ps-lap > figcaption { position: static; }
}

/* The moment notes above the look-ahead: one per phase (05:00, the huddle, Shift A, Shift B), stacked in one cell. */
#p-shift .ps-hnote {
  max-width: none;
  padding: var(--s-3) var(--s-4);
  background: var(--bg-subtle);
  border-left: 2px solid var(--teal);
  font-size: 15px;
  line-height: 1.55;
  color: var(--ink-2);
}
#p-shift .ps-hnote .mono { margin-right: 8px; color: var(--teal-ink); }

/* 7. Handover (#ps-handover) ---------------------------------------------------------------------------------------
   05:15 (n8-spec §8): the head beside one compact Shift Handover card in the newer look, with no app chrome. The card: a head (name, shift, clock, Illustrative tag); the four results as words (category, measure, value, flag, goal; never
   letter squares); the open-action summary; the first three rows of the Line Action Plan in the board's order
   (overdue, then due soon); the foot. 4/8 from 1100; stacked below, the card at most 760px. Results four across from
   720 (2×2 below). Action rows on a 64px | title | 190px | flag grid from 720; on a phone the id and title, then the
   person with the flag at the right (below 380 the person as one line, the flag under it). Real borders, not
   shadows, draw every divider, so forced colours keep them. */
#p-shift .ps-hand-grid { display: grid; gap: var(--s-5); min-width: 0; }
#p-shift .ps-hand-grid > .section-head { margin: 0; }
@media (min-width: 720px) {
  #p-shift .ps-hand-grid { gap: var(--s-6); }
}
@media (min-width: 1100px) {
  #p-shift .ps-hand-grid { grid-template-columns: minmax(0, 4fr) minmax(0, 8fr); gap: var(--s-7); align-items: start; }
}
#p-shift .ps-hob { min-width: 0; max-width: 760px; margin: 0; }
@media (min-width: 1100px) {
  #p-shift .ps-hob { max-width: none; }
}
#p-shift .ps-hob-card { overflow: hidden; background: var(--surface); border: 1px solid var(--hairline); border-radius: var(--r-card); box-shadow: var(--shadow-1); }
#p-shift .ps-hob-card p { max-width: none; margin: 0; }

/* Head: the board's name and line, Shift A's hours, the clock at the right, then the look tag. On a phone the clock
   moves up beside the name, so the hours and the tag share the second line. */
#p-shift .ps-hob-head { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 16px; padding: 12px 16px; border-bottom: 1px solid var(--hairline); }
#p-shift .ps-hob-name { display: inline-flex; align-items: center; gap: 8px; font-size: 15px; font-weight: 600; line-height: 22px; color: var(--ink); }
#p-shift .ps-hob-name .icon { width: 18px; height: 18px; color: var(--ink-3); }
#p-shift .ps-hob-shift { font-size: 13px; line-height: 20px; color: var(--ink-2); white-space: nowrap; }
#p-shift .ps-hob-shift .mono { color: inherit; }
#p-shift .ps-hob-card .ps-hob-clock { margin-left: auto; font-size: 14px; font-weight: 600; line-height: 20px; color: var(--ink-2); font-variant-numeric: tabular-nums; }
@media (max-width: 719px) {
  #p-shift .ps-hob-card .ps-hob-clock { order: 1; }
  #p-shift .ps-hob-shift { order: 2; }
  #p-shift .ps-hob-head > .tag { order: 3; }
}

/* Results: category, measure, value, then the flag and the goal. Hairlines between the cells. */
#p-shift .ps-hob-kpis { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); margin: 0; padding: 0; list-style: none; border-bottom: 1px solid var(--hairline); }
#p-shift .ps-hob-kpis li { display: flex; flex-wrap: wrap; align-content: start; align-items: center; gap: 2px 8px; min-width: 0; padding: 12px 14px; }
#p-shift :is(.ps-hob-cat, .ps-hob-k, .ps-hob-v) { flex: 1 0 100%; min-width: 0; }
#p-shift .ps-hob-cat { font-size: 12px; font-weight: 600; line-height: 16px; color: var(--ink-3); }
#p-shift .ps-hob-k { margin-top: -2px; font-size: 13px; line-height: 18px; color: var(--ink-2); }
#p-shift .ps-hob-v { margin-bottom: 2px; font-size: 22px; font-weight: 600; line-height: 26px; color: var(--ink); font-variant-numeric: tabular-nums; }
#p-shift .ps-hob-goal { font-size: 12px; line-height: 18px; color: var(--ink-3); white-space: nowrap; }
@media (max-width: 719px) {
  #p-shift .ps-hob-kpis li:nth-child(odd) { border-right: 1px solid var(--hairline); }
  #p-shift .ps-hob-kpis li:nth-child(-n+2) { border-bottom: 1px solid var(--hairline); }
}
@media (min-width: 720px) {
  #p-shift .ps-hob-kpis { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  #p-shift .ps-hob-kpis li { padding: 12px 16px; }
  #p-shift .ps-hob-kpis li + li { border-left: 1px solid var(--hairline); }
}

/* Summary: the three counts (overdue in danger ink with its icon), then the source line: floated right from 720, its
   own line on a phone. Non-breaking spaces keep each count with its word. */
#p-shift .ps-hob-sum { padding: 10px 16px; font-size: 14px; line-height: 24px; color: var(--ink-2); }
#p-shift .ps-hob-n { font-size: 20px; font-weight: 600; line-height: 24px; color: var(--ink); font-variant-numeric: tabular-nums; }
#p-shift .ps-hob-late { color: var(--danger-ink); white-space: nowrap; }
#p-shift .ps-hob-late .ps-hob-n { color: inherit; }
#p-shift .ps-hob-late .icon { display: inline-block; width: 14px; height: 14px; margin-right: 4px; vertical-align: -1px; }
#p-shift .ps-hob-src { display: block; font-size: 13px; line-height: 20px; color: var(--ink-3); }
@media (min-width: 720px) {
  #p-shift .ps-hob-sum { padding-inline: 20px; }
  #p-shift .ps-hob-src { float: right; margin-left: 16px; line-height: 24px; }
}

/* Action rows. Phone: the id and title, then the person (name over role) with the flag at the right. From 720: one
   row of four fixed columns (the flag's 144px fits its longest, "Oct 3 · 9 days late"), so the person and the flag
   line up from row to row; at least 52px. */
#p-shift .ps-hob-acts { margin: 0; padding: 0; list-style: none; border-top: 1px solid var(--hairline); }
#p-shift .ps-hob-act { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; grid-template-areas: "id t t" "who who flag"; align-items: baseline; gap: 8px 10px; padding: 10px 16px; }
#p-shift .ps-hob-act + .ps-hob-act { border-top: 1px solid var(--hairline); }
#p-shift .ps-hob-id { grid-area: id; font-size: 13px; line-height: 20px; color: var(--ink-3); }
#p-shift .ps-hob-t { grid-area: t; min-width: 0; font-size: 15px; font-weight: 600; line-height: 20px; color: var(--ink); text-wrap: balance; }
#p-shift .ps-hob-from { font-size: 13px; font-weight: 400; color: var(--ink-3); white-space: nowrap; }
#p-shift .ps-hob-act > .ps-who { grid-area: who; align-self: center; }
#p-shift .ps-hob-act > .ps-flag { grid-area: flag; align-self: center; justify-self: end; }
@media (max-width: 379px) {
  #p-shift .ps-hob-act { grid-template-columns: auto minmax(0, 1fr); grid-template-areas: "id t" "who who" "flag flag"; }
  #p-shift .ps-hob-act > .ps-flag { justify-self: start; }
  #p-shift .ps-hob-act > .ps-who { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 0 6px; }
  #p-shift .ps-hob-act > .ps-who > .ps-av { width: 22px; height: 22px; font-size: 10px; }
  #p-shift .ps-hob-act :is(.ps-who-name, .ps-who-role) { align-self: center; font-size: 13px; line-height: 18px; }
  #p-shift .ps-hob-act .ps-who-role::before { content: "· " / ""; }
}
@media (min-width: 720px) {
  #p-shift .ps-hob-act { grid-template-columns: 64px minmax(0, 1fr) 190px 144px; grid-template-areas: "id t who flag"; align-items: center; column-gap: 12px; min-height: 52px; padding: 8px 20px; }
  #p-shift .ps-hob-head { padding-inline: 20px; }
}

/* Foot: how much of the plan the card shows. */
#p-shift .ps-hob-foot { padding: 10px 16px; border-top: 1px solid var(--hairline); font-size: 13px; line-height: 20px; color: var(--ink-3); }
@media (min-width: 720px) {
  #p-shift .ps-hob-foot { padding-inline: 20px; }
}

@media (forced-colors: active) {
  #p-shift .ps-hob-card { border: 1px solid CanvasText; }
  #p-shift :is(.ps-hob-head, .ps-hob-kpis, .ps-hob-kpis li, .ps-hob-acts, .ps-hob-act, .ps-hob-foot) { border-color: CanvasText; }
  #p-shift :is(.ps-hob-name, .ps-hob-late) .icon { color: currentColor; }
}

/* 7a. One plan, many sources (D40; 05-sources, #pa-sources). Moved from page-action-planning.css §3 with its
   §8c and §9 lines (site restructure 2026-10-26), #p-actions → #p-shift ---------------------------------------- */
#p-shift .pa-inlets { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--s-4); }
@media (min-width: 640px) { #p-shift .pa-inlets { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1024px) { #p-shift .pa-inlets { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
#p-shift .pa-inlet {
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
  min-width: 0;
  padding: 20px;
  background: var(--bg-subtle);
  border: 1px solid var(--hairline);
  border-radius: var(--r-card);
}
#p-shift .pa-inlet-top { display: flex; align-items: center; gap: var(--s-3); min-width: 0; }
/* Titles below H2 (D45): two site sizes, 16px for card titles and 20px for steps and section titles. */
#p-shift .pa-inlet h3 { font-size: 16px; line-height: 1.35; }
#p-shift .pa-inlet p { font-size: 15px; line-height: 1.55; color: var(--ink-2); }
#p-shift .pa-inlet .pa-inlet-to {
  margin-top: auto;
  padding-top: var(--s-3);
  border-top: 1px dashed var(--hairline);
  font-size: 13px;
  font-weight: 600;
  line-height: 1.5;
  color: var(--ink-3);
}
/* Phone length (was §8c): below 768 the "Lands on" line steps out (each card's board is in the rows below it). */
@media (max-width: 767px) {
  #p-shift .pa-inlet { padding: 16px; }
  #p-shift .pa-inlet .pa-inlet-to { display: none; }
}
@media (forced-colors: active) { #p-shift .pa-inlet { border: 1px solid; } }

/* 7b. SMART Actions (owner brief; 04-smart, #pa-top, #4182 is #pa-anatomy). Was the /action-planning page header:
   page-action-planning.css §1 with its §0 and §9 lines (site restructure 2026-10-26), #p-actions → #p-shift ---- */
/* 7/5 on the inner header's grid (.page-header-grid, site.css section 23): the section head and the SMART rail on the
   left, #4182 built letter by letter on the right. The base styles are the finished record with all five letters lit:
   that is what reduced motion (site.css section 33) and a chosen letter show. The play (about 14 s) opens on the saved
   drawer. The scroll drives it wherever the section, or its rail and #4182, fits the screen (.is-scrolly, 7b.3: the
   section pins and next-8-hours.js sets the play's time from the scroll); elsewhere it plays once when it comes into
   view (next-8-hours.js holds it at its first frame until then, .is-wait in 7b.3), or on load without the script. The
   timeline is the variables below. */
#p-shift .pa-smart {
  /* One pace for every beat: about 0.6 s between its changes and about 1 s of hold after the last, so a busy letter
     runs longer than a one-change letter. A beat's length is its --l (7b.3); the next beat starts where it ends. */
  --sx-S: 0.6s;  /* S 0.6-3.7: "Fix the filler" struck (0.9), the specific title (1.5), problem (2.1), owner (2.7) */
  --sx-M: 3.7s;  /* M 3.7-5.3: the linked KPI pill (3.9) */
  --sx-A: 5.3s;  /* A 5.3-8.5: Escalate pressed (5.6), the path up on Packaging and De-escalate (6.1), De-escalate
                    pressed (6.9), the path back on Line 4 (7.2-7.4) */
  --sx-R: 8.5s;  /* R 8.5-10.1: the board path and the type chip (8.6) */
  --sx-T: 10.1s; /* T 10.1-13.4: Daily, Oct 19 and Due (10.2), amber (11.0), red and how late (11.9-12.7); rest 13.4 */
  /* Before S: the saved drawer, still titled "Fix the filler" (0-0.6). Owner 2026-10-30: the play starts here; the
     Headline KPIs tile and Take action that came before it are gone. */
  --sx-span: calc(var(--sx-T) + 3.3s - var(--sx-S));  /* S to the rest: the record out of focus around each beat */
  /* Out of focus: the rest of #4182 while a letter is chosen or its beat plays (7b.2). */
  --sx-dim-o: 0.4; --sx-dim-f: blur(1.5px);
  --sx-in: pa-sx-in; --sx-win: pa-sx-win; --sx-lit: pa-sx-lit; --sx-now: pa-sx-now;
  --sx-dim: pa-sx-dim; --sx-lift: pa-sx-lift; --sx-lift-s: pa-sx-lift-s; --sx-lift-t: pa-sx-lift-t;
  --sx-tap: pa-sx-tap; --sx-strike: pa-sx-strike;
  --sx-due: pa-sx-due; --sx-late: pa-sx-late; --sx-date: pa-sx-date;
}
/* REVIEW ONLY (?look=fade, 04-smart.php): fade without the blur, to compare. Drop with the switch once one is picked. */
#p-shift .pa-smart[data-sx-look="fade"] { --sx-dim-o: 0.3; --sx-dim-f: blur(0px); }
/* Replay: a CSS animation restarts only when its name changes, so #pa-sx-1 plays the -b copies and #pa-sx-2 the
   first set again; each replay label shows while the other radio is the checked one. A letter stops the play. */
#p-shift .pa-smart:has(#pa-sx-1:checked) {
  --sx-in: pa-sx-in-b; --sx-win: pa-sx-win-b; --sx-lit: pa-sx-lit-b; --sx-now: pa-sx-now-b;
  --sx-dim: pa-sx-dim-b; --sx-lift: pa-sx-lift-b; --sx-lift-s: pa-sx-lift-s-b; --sx-lift-t: pa-sx-lift-t-b;
  --sx-tap: pa-sx-tap-b; --sx-strike: pa-sx-strike-b;
  --sx-due: pa-sx-due-b; --sx-late: pa-sx-late-b; --sx-date: pa-sx-date-b;
}
/* A letter stops the play, and so does the rest a mouse leaves behind (#pa-sx-x, next-8-hours.js). */
#p-shift .pa-smart:has(:is(#pa-sx-s, #pa-sx-m, #pa-sx-a, #pa-sx-r, #pa-sx-t, #pa-sx-x):checked) {
  --sx-in: none; --sx-win: none; --sx-lit: none; --sx-now: none;
  --sx-dim: none; --sx-lift: none; --sx-lift-s: none; --sx-lift-t: none;
  --sx-tap: none; --sx-strike: none; --sx-due: none; --sx-late: none; --sx-date: none;
}
/* A section now (it was the page header): the head sits in the copy column over the rail, which keeps its own top
   margin, and the header's extra top padding is gone. */
#p-shift .pa-smart .section-head { margin-bottom: 0; }
@media (min-width: 1024px) {
  #p-shift .pa-smart .page-header-visual { align-self: center; }
}
/* Escalate on a saved drawer: the primary-soft button (D39, D42). Section helper: §49h has no soft variant. Was §0. */
#p-shift .app .pa-btn-soft { background: var(--app-primary-soft); border-color: var(--app-primary-line); color: var(--app-primary-dark); }

/* 7b.1 The SMART rail: a letter tile, the word run in, one line on how the product helps. Each row is the label of a
   radio (.state-input, site.css section 45); the group wrapper takes no grid cell. */
#p-shift .pa-sx-radios { position: absolute; width: 0; height: 0; }
/* Set only by script; out of the arrow-key order. */
#p-shift #pa-sx-x { display: none; }
#p-shift .pa-sx-rail {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--s-2) var(--s-3);
  min-width: 0;
  margin-top: var(--s-6);
}
#p-shift .pa-sx-k { font-size: 13px; font-weight: 600; line-height: 1.5; color: var(--ink-3); }
#p-shift .pa-sx-replay {
  grid-column: 2;
  grid-row: 1;
  display: inline-flex;
  align-items: center;
  min-height: 32px;
  padding: 0 12px;
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-control);
  font-size: 14px;
  font-weight: 500;
  color: var(--ink-2);
  cursor: pointer;
  transition: background-color var(--t-fast) ease-out, color var(--t-fast) ease-out;
}
#p-shift .pa-sx-replay:hover { background: var(--bg-subtle); color: var(--ink); }
#p-shift .pa-sx-replay--2 { display: none; }
#p-shift .pa-smart:has(#pa-sx-1:checked) .pa-sx-replay--1 { display: none; }
#p-shift .pa-smart:has(#pa-sx-1:checked) .pa-sx-replay--2 { display: inline-flex; }
/* No motion, nothing to replay. */
@media (prefers-reduced-motion: reduce) {
  #p-shift .pa-sx-replay { display: none !important; }
  /* Nor their radios, so arrowing never lands on an unseen, idle Replay. */
  #p-shift :is(#pa-sx-1, #pa-sx-2) { display: none; }
}
#p-shift .pa-sx-list { grid-column: 1 / -1; display: grid; gap: 2px; padding-top: 4px; border-top: 1px solid var(--hairline); }
#p-shift .pa-sx-l {
  position: relative;
  display: block;
  min-height: 52px;
  padding: 7px 10px 7px 58px;
  border: 1px solid transparent;
  border-radius: var(--r-card);
  font-size: 15px;
  line-height: 1.45;
  color: var(--ink-2);
  cursor: pointer;
  transition: background-color var(--t-fast) ease-out, border-color var(--t-fast) ease-out;
}
#p-shift .pa-sx-l:hover { background: var(--bg-subtle); }
#p-shift .pa-sx-tab { display: contents; }
/* Lit: the accent fill. Unlit (only while playing, before its beat): the neutral chip. */
#p-shift .pa-sx-ltr {
  position: absolute;
  top: 8px;
  left: 10px;
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  border: 1px solid var(--action);
  border-radius: var(--r-card);
  background: var(--action);
  font-size: 18px;
  font-weight: 700;
  line-height: 1;
  color: var(--white);
}
#p-shift .pa-sx-w { margin-right: 6px; font-weight: 600; color: var(--ink); }
#p-shift .pa-sx-hint { grid-column: 1 / -1; font-size: 14px; line-height: 1.5; color: var(--ink-3); }
/* One wording at a time (R1·6): hover with the autoplay, the jump in scroll mode (.is-scrolly, 7b.3), where hover
   chooses nothing and a letter takes the pinned page to its beat; no script, the hover one. Spans, so the hint's own
   fade-in (7b.3) never restarts when next-8-hours.js tries scroll mode on to measure. */
#p-shift .pa-smart:not(.is-scrolly) .pa-sx-hint-scroll,
#p-shift .pa-smart.is-scrolly .pa-sx-hint-hover { display: none; }
#p-shift .pa-sx-rail .kbd-hint { grid-column: 1 / -1; margin-top: 0; }
/* Chosen: the selected tint (as the anatomy's callouts were). The label paints on desktop, the tab on phone. */
#p-shift .pa-smart:has(#pa-sx-s:checked) :is(label[for="pa-sx-s"], label[for="pa-sx-s"] .pa-sx-tab),
#p-shift .pa-smart:has(#pa-sx-m:checked) :is(label[for="pa-sx-m"], label[for="pa-sx-m"] .pa-sx-tab),
#p-shift .pa-smart:has(#pa-sx-a:checked) :is(label[for="pa-sx-a"], label[for="pa-sx-a"] .pa-sx-tab),
#p-shift .pa-smart:has(#pa-sx-r:checked) :is(label[for="pa-sx-r"], label[for="pa-sx-r"] .pa-sx-tab),
#p-shift .pa-smart:has(#pa-sx-t:checked) :is(label[for="pa-sx-t"], label[for="pa-sx-t"] .pa-sx-tab) {
  background: var(--tint);
  border-color: var(--tint-border);
}
#p-shift .pa-smart:has(#pa-sx-0:focus-visible) .pa-sx-list,
#p-shift .pa-smart:has(#pa-sx-s:focus-visible) :is(label[for="pa-sx-s"], label[for="pa-sx-s"] .pa-sx-tab),
#p-shift .pa-smart:has(#pa-sx-m:focus-visible) :is(label[for="pa-sx-m"], label[for="pa-sx-m"] .pa-sx-tab),
#p-shift .pa-smart:has(#pa-sx-a:focus-visible) :is(label[for="pa-sx-a"], label[for="pa-sx-a"] .pa-sx-tab),
#p-shift .pa-smart:has(#pa-sx-r:focus-visible) :is(label[for="pa-sx-r"], label[for="pa-sx-r"] .pa-sx-tab),
#p-shift .pa-smart:has(#pa-sx-t:focus-visible) :is(label[for="pa-sx-t"], label[for="pa-sx-t"] .pa-sx-tab),
#p-shift .pa-smart:has(:is(#pa-sx-1, #pa-sx-2):focus-visible) .pa-sx-replay {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}
/* Phone: the five letters become one row of tabs (word under the letter); the chosen letter's line sits under the
   row, all five lines and the hint stacked in one cell so the row never changes height. */
@media (max-width: 639px) {
  #p-shift .pa-sx-rail { grid-template-columns: repeat(5, minmax(0, 1fr)); gap: var(--s-2) 4px; }
  #p-shift .pa-sx-k { grid-column: 1 / 4; grid-row: 1; }
  #p-shift .pa-sx-replay { grid-column: 4 / -1; justify-self: end; }
  #p-shift :is(.pa-sx-list, .pa-sx-l) { display: contents; }
  #p-shift .pa-sx-tab {
    grid-row: 2;
    align-self: start;
    display: grid;
    justify-items: center;
    gap: 4px;
    min-width: 0;
    padding: 6px 2px;
    border: 1px solid transparent;
    border-radius: var(--r-card);
    cursor: pointer;
  }
  #p-shift .pa-sx-ltr { position: static; }
  /* One line per word, so the five letters stay level. */
  #p-shift .pa-sx-w { margin: 0; font-size: 11px; line-height: 1.3; white-space: nowrap; }
  #p-shift :is(.pa-sx-t, .pa-sx-hint) { grid-row: 3; grid-column: 1 / -1; align-self: start; font-size: 15px; line-height: 1.45; }
  #p-shift .pa-sx-t { visibility: hidden; color: var(--ink-2); }
  #p-shift .pa-sx-rail .kbd-hint { grid-row: 4; }
  #p-shift .pa-smart:has(#pa-sx-s:checked) label[for="pa-sx-s"] .pa-sx-t,
  #p-shift .pa-smart:has(#pa-sx-m:checked) label[for="pa-sx-m"] .pa-sx-t,
  #p-shift .pa-smart:has(#pa-sx-a:checked) label[for="pa-sx-a"] .pa-sx-t,
  #p-shift .pa-smart:has(#pa-sx-r:checked) label[for="pa-sx-r"] .pa-sx-t,
  #p-shift .pa-smart:has(#pa-sx-t:checked) label[for="pa-sx-t"] .pa-sx-t { visibility: visible; }
  #p-shift .pa-smart:has(:is(#pa-sx-s, #pa-sx-m, #pa-sx-a, #pa-sx-r, #pa-sx-t):checked) .pa-sx-hint { visibility: hidden; }
}
@media (max-width: 379px) { #p-shift .pa-sx-w { font-size: 10px; } }

/* 7b.2 #4182 in .app: the saved drawer. Layers marked aria-hidden are hidden at rest and shown by a window. */
#p-shift .pa-sx-fig { min-width: 0; max-width: 520px; margin: 0; }
#p-shift .pa-sx-stage { display: grid; }
#p-shift :is(.pa-sx-stage, .pa-sx-stack) > * { grid-area: 1 / 1; }
#p-shift .pa-sx-drawer { width: 100%; margin: 0; }
#p-shift .pa-sx-stack { display: grid; justify-items: start; min-width: 0; }
#p-shift :is(.pa-sx-vague, .pa-sx-up, .pa-sx-de) { visibility: hidden; }
/* The header's two stacks: the gap moves out of the title and the path, so a field's outline clears its neighbour. */
#p-shift .pa-sx-drawer .app-drawer-h .pa-sx-stack { margin-top: 7px; }
#p-shift .pa-sx-stack > :is(.app-drawer-t, .app-drawer-path) { margin-top: 0; }
/* The draft title: muted, struck through as S lands. The Packaging path covers the Line 4 path (same cell, opaque). */
#p-shift .pa-sx-vague { position: relative; color: var(--app-mute); }
#p-shift .pa-sx-vague::after {
  content: "";
  position: absolute;
  left: -2px;
  right: -2px;
  top: 55%;
  height: 2px;
  background: var(--app-ink-2);
  transform-origin: left center;
}
#p-shift .pa-sx-up { justify-self: stretch; background: var(--app-card); }
#p-shift .pa-sx-ps { font-size: var(--app-fs-sm); line-height: 1.45; color: var(--app-ink-2); }
#p-shift :is(.pa-sx-kpi, .pa-sx-owner) { transform-origin: left center; }
/* T: Daily and the due pill share one outline. "2d late" sits under "Oct 19" in one cell and the play swaps them, so
   the pill keeps its width and the chip row never rewraps. The late text's negative margins leave the width to the
   date (the row fits 360 to the pixel); the pixel or so it is wider runs into the pill's padding. */
#p-shift .pa-sx-when { display: flex; gap: 6px; border-radius: var(--app-r-round); }
#p-shift .pa-sx-due { display: inline-grid; }
#p-shift .pa-sx-due > * { grid-area: 1 / 1; justify-self: center; }
#p-shift .pa-sx-late { margin-inline: -4px; visibility: hidden; }
/* A field stays in focus while its beat plays and when its letter is chosen; the rest of the record (the other
   fields and the .pa-sx-u parts: the app bar's mark and crumb, #4182, the close icon, Ready, Close) fades and softens around it. Only these leaves
   fade, never a box around them, so nothing fades twice. :where() keeps the radius (for the forced-colors outline,
   7b.4) below section 49's, so a pill or chip keeps its own. */
:where(#p-shift) .pa-sx-f { border-radius: var(--r-control); }
#p-shift :is(.pa-sx-f, .pa-sx-u) { transition: opacity 0.25s ease-out, filter 0.25s ease-out; }
#p-shift .pa-smart:has(:is(#pa-sx-s, #pa-sx-m, #pa-sx-a, #pa-sx-r, #pa-sx-t):checked) :is(.pa-sx-f, .pa-sx-u) {
  opacity: var(--sx-dim-o);
  filter: var(--sx-dim-f);
}
#p-shift .pa-smart:has(#pa-sx-s:checked) .pa-sx-f--s,
#p-shift .pa-smart:has(#pa-sx-m:checked) .pa-sx-f--m,
#p-shift .pa-smart:has(#pa-sx-a:checked) .pa-sx-f--a,
#p-shift .pa-smart:has(#pa-sx-r:checked) .pa-sx-f--r,
#p-shift .pa-smart:has(#pa-sx-t:checked) .pa-sx-f--t { opacity: 1; filter: none; }

/* 7b.3 The play. Each beat's start and length ride on --b and --l (set per letter and per field), so one rule per
   part draws the whole timeline; --k is the field's focus keyframes (S comes in already sharp, T stays sharp into the
   rest). Fill modes: "in" holds its from-state until its delay (backwards); a window shows a hidden layer only while
   it runs (no fill). */
#p-shift label[for="pa-sx-s"], #p-shift .pa-sx-f--s { --b: var(--sx-S); --l: 3.1s; --k: var(--sx-lift-s); }
#p-shift label[for="pa-sx-m"], #p-shift .pa-sx-f--m { --b: var(--sx-M); --l: 1.6s; --k: var(--sx-lift); }
#p-shift label[for="pa-sx-a"], #p-shift .pa-sx-f--a { --b: var(--sx-A); --l: 3.2s; --k: var(--sx-lift); }
#p-shift label[for="pa-sx-r"], #p-shift .pa-sx-f--r { --b: var(--sx-R); --l: 1.6s; --k: var(--sx-lift); }
#p-shift label[for="pa-sx-t"], #p-shift .pa-sx-f--t { --b: var(--sx-T); --l: 3.3s; --k: var(--sx-lift-t); }
@media (prefers-reduced-motion: no-preference) {
  #p-shift :is(.pa-sx-l, .pa-sx-tab) { animation: var(--sx-now) var(--l) linear var(--b); }
  #p-shift .pa-sx-ltr { animation: var(--sx-lit) 0.4s ease-out var(--b) backwards; }
  #p-shift .pa-sx-hint { animation: var(--sx-in) 0.4s ease-out calc(var(--sx-T) + 3.5s) backwards; }
  /* From S to the rest the record is out of focus; a field comes into focus through its beat (the later animation
     wins), and the parts inside arrive on cue. */
  #p-shift .pa-sx-u { animation: var(--sx-dim) var(--sx-span) linear var(--sx-S); }
  #p-shift .pa-sx-f { animation: var(--sx-dim) var(--sx-span) linear var(--sx-S), var(--k) var(--l) linear var(--b); }
  /* The draft title is up as the play opens (a negative delay starts its window 0.4 s in, past the fade-in) and gives
     way to the specific title (S + 0.95). */
  #p-shift .pa-sx-vague { animation: var(--sx-win) 1.95s linear -0.4s; }
  #p-shift .pa-sx-vague::after { animation: var(--sx-strike) 0.35s ease-out calc(var(--sx-S) + 0.3s) backwards; }
  #p-shift .pa-sx-title { animation: var(--sx-in) 0.35s ease-out calc(var(--sx-S) + 0.9s) backwards; }
  #p-shift .pa-sx-ps { animation: var(--sx-in) 0.35s ease-out calc(var(--sx-S) + 1.5s) backwards; }
  #p-shift .pa-sx-owner { --sx-from: scale(0.85); animation: var(--sx-in) 0.3s ease-out calc(var(--sx-S) + 2.1s) backwards; }
  #p-shift .pa-sx-kpi { --sx-from: scale(0.85); animation: var(--sx-in) 0.3s ease-out calc(var(--sx-M) + 0.2s) backwards; }
  #p-shift .pa-sx-esc { animation: var(--sx-dim) var(--sx-span) linear var(--sx-S), var(--k) var(--l) linear var(--b), var(--sx-tap) 0.3s ease-out calc(var(--sx-A) + 0.3s); }
  /* The board path is A then R back to back: one focus window across both, so it doesn't blink between them. */
  #p-shift .pa-sx-f--a.pa-sx-f--r { animation: var(--sx-dim) var(--sx-span) linear var(--sx-S), var(--sx-lift) 4.8s linear var(--sx-A); }
  #p-shift .pa-sx-up { animation: var(--sx-win) 1.3s linear calc(var(--sx-A) + 0.8s); }
  #p-shift .pa-sx-de { animation: var(--sx-win) 1.6s linear calc(var(--sx-A) + 0.8s), var(--sx-tap) 0.3s ease-out calc(var(--sx-A) + 1.6s); }
  /* "in" last, so its held opacity 0 wins over the focus pair until the chip arrives. */
  #p-shift .pa-sx-type { animation: var(--sx-dim) var(--sx-span) linear var(--sx-S), var(--k) var(--l) linear var(--b), var(--sx-in) 0.3s ease-out calc(var(--b) + 0.1s) backwards; }
  #p-shift .pa-sx-cad { animation: var(--sx-in) 0.3s ease-out calc(var(--sx-T) + 0.1s) backwards; }
  #p-shift .pa-sx-dued { animation: var(--sx-in) 0.3s ease-out calc(var(--sx-T) + 0.2s) backwards; }
  /* The due pill: amber three days out (12.8), red with "2d late" in place of the date once it passes (13.7-14.5), back
     to Oct 19. */
  #p-shift .pa-sx-due { animation: var(--sx-in) 0.3s ease-out calc(var(--sx-T) + 0.1s) backwards, var(--sx-due) 1.8s linear calc(var(--sx-T) + 0.9s); }
  #p-shift .pa-sx-late { animation: var(--sx-late) 1.8s linear calc(var(--sx-T) + 0.9s); }
  #p-shift .pa-sx-d { animation: var(--sx-date) 1.8s linear calc(var(--sx-T) + 0.9s); }
}
@media (prefers-reduced-motion: no-preference) and (max-width: 639px) {
  #p-shift .pa-sx-t { animation: var(--sx-win) var(--l) linear var(--b); }
}
/* The wait (next-8-hours.js): while #pa-top is still off screen, the script sets .is-wait and every part of the play
   holds at its first frame; it runs once the section is in view. Paused, not removed, so the start never jumps. After
   the play rules, so it wins at equal specificity (the A-and-R path). No script, no .is-wait: it plays on load. */
#p-shift .pa-smart.is-wait *,
#p-shift .pa-smart.is-wait *::after { animation-play-state: paused; }
/* The scroll (owner 2026-10-30, the huddle's scroll mode, then on phones too; next-8-hours.js adds .is-scrolly and
   sets the custom properties). The section's content sticks at --sx-pin-top while the page scrolls through --sx-run of
   track below it (the ::after), and the script holds every part of the play at the time the scroll gives it, so
   scrolling back up plays it backwards. Stacked, --sx-pin-top is set so the head sits above the screen's top or under
   the opaque site header and the rail (or the letter tabs) and #4182 pin; the drawn app zooms (--sx-zoom) when even
   that is too tall. Replay and its radios go (the scroll is the replay; the radios stay out of the arrow-key order),
   and the rail's hint says a letter jumps (7b.1).
   Print gets the plain section. */
#p-shift .pa-smart.is-scrolly > .container { position: sticky; top: var(--sx-pin-top, 72px); }
#p-shift .pa-smart.is-scrolly .pa-sx-fig { zoom: var(--sx-zoom, 1); }
#p-shift .pa-smart.is-scrolly::after { content: ""; display: block; height: var(--sx-run, 0px); }
#p-shift .pa-smart.is-scrolly .pa-sx-replay { display: none !important; }
#p-shift .pa-smart.is-scrolly :is(#pa-sx-1, #pa-sx-2) { display: none; }
@media print {
  #p-shift .pa-smart.is-scrolly > .container { position: static; }
  #p-shift .pa-smart.is-scrolly::after { display: none; }
  #p-shift .pa-smart.is-scrolly .pa-sx-fig { zoom: 1; }
}
/* Two identical sets (see Replay above). */
@keyframes pa-sx-in { from { opacity: 0; transform: var(--sx-from, translateY(6px)); } }
@keyframes pa-sx-in-b { from { opacity: 0; transform: var(--sx-from, translateY(6px)); } }
@keyframes pa-sx-win { 0% { visibility: visible; opacity: 0; } 15%, 85% { visibility: visible; opacity: 1; } 100% { visibility: visible; opacity: 0; } }
@keyframes pa-sx-win-b { 0% { visibility: visible; opacity: 0; } 15%, 85% { visibility: visible; opacity: 1; } 100% { visibility: visible; opacity: 0; } }
@keyframes pa-sx-lit { from { background: var(--neutral-fill); border-color: var(--hairline); color: var(--ink-3); } 60% { transform: scale(1.12); } }
@keyframes pa-sx-lit-b { from { background: var(--neutral-fill); border-color: var(--hairline); color: var(--ink-3); } 60% { transform: scale(1.12); } }
@keyframes pa-sx-now { 10%, 85% { background-color: var(--tint); border-color: var(--tint-border); } }
@keyframes pa-sx-now-b { 10%, 85% { background-color: var(--tint); border-color: var(--tint-border); } }
/* Out of focus from S to the rest (fades in over ~0.25 s, back over ~0.5 s); a field's beat brings it into focus. */
@keyframes pa-sx-dim { 0%, 100% { opacity: 1; filter: blur(0px); } 2%, 96% { opacity: var(--sx-dim-o); filter: var(--sx-dim-f); } }
@keyframes pa-sx-dim-b { 0%, 100% { opacity: 1; filter: blur(0px); } 2%, 96% { opacity: var(--sx-dim-o); filter: var(--sx-dim-f); } }
@keyframes pa-sx-lift { 0%, 100% { opacity: var(--sx-dim-o); filter: var(--sx-dim-f); } 12%, 88% { opacity: 1; filter: blur(0px); } }
@keyframes pa-sx-lift-b { 0%, 100% { opacity: var(--sx-dim-o); filter: var(--sx-dim-f); } 12%, 88% { opacity: 1; filter: blur(0px); } }
@keyframes pa-sx-lift-s { 0%, 88% { opacity: 1; filter: blur(0px); } 100% { opacity: var(--sx-dim-o); filter: var(--sx-dim-f); } }
@keyframes pa-sx-lift-s-b { 0%, 88% { opacity: 1; filter: blur(0px); } 100% { opacity: var(--sx-dim-o); filter: var(--sx-dim-f); } }
@keyframes pa-sx-lift-t { 0% { opacity: var(--sx-dim-o); filter: var(--sx-dim-f); } 12%, 100% { opacity: 1; filter: blur(0px); } }
@keyframes pa-sx-lift-t-b { 0% { opacity: var(--sx-dim-o); filter: var(--sx-dim-f); } 12%, 100% { opacity: 1; filter: blur(0px); } }
@keyframes pa-sx-tap { 50% { transform: scale(0.95); box-shadow: inset 0 2px 3px var(--app-scrim); } }
@keyframes pa-sx-tap-b { 50% { transform: scale(0.95); box-shadow: inset 0 2px 3px var(--app-scrim); } }
@keyframes pa-sx-strike { from { transform: scaleX(0); } }
@keyframes pa-sx-strike-b { from { transform: scaleX(0); } }
/* Due soon, then late: the .soon and .late pill colours (site.css section 49). */
@keyframes pa-sx-due { 0%, 40% { background-color: var(--app-warn-soft); color: var(--app-warn-ink); } 45%, 90% { background-color: var(--app-bad-soft); color: var(--app-bad-ink); } }
@keyframes pa-sx-due-b { 0%, 40% { background-color: var(--app-warn-soft); color: var(--app-warn-ink); } 45%, 90% { background-color: var(--app-bad-soft); color: var(--app-bad-ink); } }
/* The swap rides the red window (45-90%). Visibility steps to "visible" anywhere between a hidden and a visible stop,
   so "2d late" needs hard stops on both edges; the date only needs its hidden pair. */
@keyframes pa-sx-late { 0%, 44.9%, 90.1%, 100% { visibility: hidden; } 45%, 90% { visibility: visible; } }
@keyframes pa-sx-late-b { 0%, 44.9%, 90.1%, 100% { visibility: hidden; } 45%, 90% { visibility: visible; } }
@keyframes pa-sx-date { 45%, 90% { visibility: hidden; } }
@keyframes pa-sx-date-b { 45%, 90% { visibility: hidden; } }

/* 7b.4 Forced colors (was §9): the rail's edges, the strike, and an outline in place of the fade. */
@media (forced-colors: active) {
  #p-shift .pa-sx-l, #p-shift .pa-sx-tab, #p-shift .pa-sx-replay { border: 1px solid; }
  #p-shift .pa-sx-vague::after { forced-color-adjust: none; background: CanvasText; }
  /* No fade or blur here (it can wash out system colours); a chosen letter's fields take an outline instead. */
  #p-shift .pa-smart { --sx-dim-o: 1; --sx-dim-f: blur(0px); }
  #p-shift .pa-smart:has(#pa-sx-s:checked) .pa-sx-f--s,
  #p-shift .pa-smart:has(#pa-sx-m:checked) .pa-sx-f--m,
  #p-shift .pa-smart:has(#pa-sx-a:checked) .pa-sx-f--a,
  #p-shift .pa-smart:has(#pa-sx-r:checked) .pa-sx-f--r,
  #p-shift .pa-smart:has(#pa-sx-t:checked) .pa-sx-f--t { outline: 2px solid Highlight; outline-offset: 3px; }
  /* The tint is dropped here, so the chosen letter takes an outline (the label on desktop, the tab on phone). */
  #p-shift .pa-smart:has(#pa-sx-s:checked) :is(label[for="pa-sx-s"], label[for="pa-sx-s"] .pa-sx-tab),
  #p-shift .pa-smart:has(#pa-sx-m:checked) :is(label[for="pa-sx-m"], label[for="pa-sx-m"] .pa-sx-tab),
  #p-shift .pa-smart:has(#pa-sx-a:checked) :is(label[for="pa-sx-a"], label[for="pa-sx-a"] .pa-sx-tab),
  #p-shift .pa-smart:has(#pa-sx-r:checked) :is(label[for="pa-sx-r"], label[for="pa-sx-r"] .pa-sx-tab),
  #p-shift .pa-smart:has(#pa-sx-t:checked) :is(label[for="pa-sx-t"], label[for="pa-sx-t"] .pa-sx-tab) { outline: 2px solid Highlight; outline-offset: 2px; }
}

/* 8. Closing band (#ps-next) ---------------------------------------------------------------------------------------
   The page's last section, #ps-next, is now the site's closing band (Main::closingBand(), site.css §24a; 2026-10-28),
   so it has no page rules; the number stays so no block is renumbered. The status rows that sat beside it (#ps-status)
   are parked in content/views/next-8-hours/.parking-lot/08-status.css. */

/* Forced colors: custom marks keep a visible shape (the .app parts have their own rules in site.css §49x). Pruned
   2026-10-28 to the huddle's marks (03-huddle.php, next-8-hours.js); the redesigned blocks carry their own rules. */
@media (forced-colors: active) {
  #p-shift .ps-look-mark { forced-color-adjust: none; background: CanvasText; }
  #p-shift .ps-look-mark::before { background: CanvasText; box-shadow: 0 0 0 2px Canvas; }
  #p-shift :is(.ps-look-bar, .ps-h-replay) { border: 1px solid; }
  #p-shift :is(.ps-q-yes, .ps-q-no) { forced-color-adjust: none; background: Canvas; border-color: CanvasText; box-shadow: none; }
  #p-shift .ps-q[data-state="y"] .ps-q-yes, #p-shift .ps-q[data-state="n"] .ps-q-no { background: CanvasText; }
  #p-shift :is(.ps-pop, .ps-drw, .ps-kc, .ps-kc-strip) { border: 1px solid; }
  #p-shift .ps-tr[data-state~="hl"] { outline: 2px solid Highlight; outline-offset: -2px; }
  #p-shift :is(.ps-lr-ring, .ps-star, .ps-kc-dot, .ps-kc-meter > .meter-fill) { forced-color-adjust: none; }
}
