/* ═══════════════════════════════════════════════════════════════════
   THE FLAT LIST
   ═══════════════════════════════════════════════════════════════════
   2026-09-07.

   Daryan: "i want the handbook page to look just as sleek as the homepage."

   The homepage reads well because its lists are INVISIBLE - .twf-pt-row is
   background:none, border:0, and the content sits directly on the canvas
   with a rail icon and a chevron. Nothing is boxed. The eye follows a single
   column of text.

   The handbook does the opposite. Every one of its 113 items is an
   .accordion-item: a 1px border, a radius, a white fill, and an 8px gap to
   the next one. That is 113 boxes stacked vertically, each announcing its
   own edges, and it is why the page feels heavy and dated next to Today.

   The counts across the app, at render sites:

       panel        788
       card         223
       twf-pt-row    25

   So the flat pattern exists and is used in 25 places, against roughly a
   thousand boxed ones. This file is the pattern written down as something
   reusable, rather than restyling one screen and leaving the next person to
   guess.

   ── WHY A SEPARATE FILE AND A SCOPED SELECTOR ───────────────────────
   .accordion-item is used outside the handbook. Restyling it globally would
   silently change screens nobody looked at, which is the exact habit that
   produced the current inconsistency. Everything here is scoped to
   .twf-flat, applied per container, so a screen opts in.

   The shift screens (task #85) and the glossary want this same treatment.
   When they take it, they add the class - they do not get their own copy.
   ═══════════════════════════════════════════════════════════════════ */

/* ═══════════════════════════════════════════════════════════════════
   THE RAIL: hints of colour, one rule
   ═══════════════════════════════════════════════════════════════════
   Daryan: "some things colored, some not... the outline of the icons should
   be colored for groupings and just brightness."

   That was not a taste problem, it was a missing stylesheet. The markup
   already asks for seven rail variants:

       r-info  r-person  r-mute  r-warn  r-ok  r-late  r-gold

   and exactly one of them had a rule - .rail.r-gold. The other six rendered
   with no tint and no stroke colour, which is precisely why some icons
   looked deliberate and others looked forgotten.

   THE RULE, stated once so it can be checked:
     stroke  carries the GROUPING  - which kind of thing this row is
     tint    carries the same hue at ~10%, so the shape reads at a glance
     nothing else colours. No filled tiles, no per-icon decisions.

   Brightness, not hue, is what changes for state: a muted row drops to
   --pt-mute, it does not change colour. That keeps hue meaningful - if
   everything can be any colour, colour stops being information.

   The tokens already existed (--pt-ok, --pt-warn, --pt-late, --pt-info,
   --pt-gold, --pt-mute) and are used by pills elsewhere, so a green rail and
   a green pill are the same green by construction rather than by memory.
   ═══════════════════════════════════════════════════════════════════ */

.rail {
  color: var(--pt-ink-soft, rgba(12, 18, 32, .7));
  background: rgba(12, 18, 32, .05);
}

.rail.r-ok      { color: var(--pt-ok);    background: var(--pt-ok-bg,   rgba(46, 125, 82, .10)); }
.rail.r-warn    { color: var(--pt-warn);  background: var(--pt-warn-bg, rgba(168, 133, 42, .12)); }
.rail.r-late    { color: var(--pt-late);  background: var(--pt-late-bg, rgba(179, 38, 30, .10)); }
.rail.r-info    { color: var(--pt-info);  background: var(--pt-info-bg, rgba(37, 99, 235, .10)); }
.rail.r-gold    { color: var(--pt-gold-strong, #A8852A); background: rgba(201, 168, 76, .12); }
.rail.r-person  { color: var(--pt-navy, #0C1220);        background: rgba(12, 18, 32, .06); }
/* Muted is the one that drops brightness rather than changing hue - it is a
   state, not a category. */
.rail.r-mute    { color: var(--pt-mute, rgba(12, 18, 32, .45)); background: rgba(12, 18, 32, .04); }

/* The icon inherits the rail's colour, so the STROKE is what carries it -
   there is no separate fill to keep in sync.

   2026-09-07: one stroke, stated once. Two per-context rules in the cockpit
   CSS (.twf-pt-row .rail svg, .twf-su-opt .rail svg) each restated
   stroke-width 2 and round caps; the registry draws 3 and square. So a
   registry icon in a rail was redrawn by whichever rule was nearest. Inside
   a rail, every icon is 2.2 with round caps - the weight that reads as
   quiet next to 15px text. The registry's heavier stroke is for icons
   standing alone (the thumb bar, a header control). Those two rules now
   set only size. */
.rail svg,
.rail svg.twf-i {
  stroke: currentColor;
  fill: none;
  stroke-width: 2.2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* ── The More sheet's icons ──────────────────────────────────────────
   Same rail, same rule. They were gradient chips with a white stroke. */
.twf-sheet-tile-icon.rail {
  width: 40px;
  height: 40px;
  border-radius: 12px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.twf-sheet-tile-icon.rail svg { width: 20px; height: 20px; }

/* ── The thumb bar ───────────────────────────────────────────────────
   Daryan: "the outline of the icons should be colored for groupings and
   just brightness. at the thumb nav row and the 'more' drawer."

   Each tab carries its group's hue on the stroke. Rest is the hue at 45%,
   active is the hue at full - brightness is the state, hue is the group,
   and the 20px bar above the active tab stays for anyone who cannot see
   hue. Labels stay ink: the words are not the grouping, the icons are. */
@media (max-width: 768px) {
  .twf-bn-btn[data-nav-bucket="today"]       { --bn-hue: var(--pt-gold-strong, #A8852A); }
  .twf-bn-btn[data-nav-bucket="shifts"],
  .twf-bn-btn[data-nav-bucket="clock"],
  .twf-bn-btn[data-nav-bucket="tools"]       { --bn-hue: var(--pt-info, #2563EB); }
  .twf-bn-btn[data-nav-bucket="chat"]        { --bn-hue: var(--pt-ok, #2E7D52); }
  .twf-bn-btn[data-nav-bucket="reviews"],
  .twf-bn-btn[data-nav-bucket="alerts"]      { --bn-hue: var(--pt-warn, #A8852A); }
  .twf-bn-btn[data-nav-bucket="voice"]       { --bn-hue: var(--pt-late, #B3261E); }
  .twf-bn-btn[data-nav-bucket="people"],
  .twf-bn-btn[data-nav-bucket="leaderboard"] { --bn-hue: var(--pt-navy, #0C1220); }

  .twf-bn-btn .twf-bn-icon {
    color: color-mix(in srgb, var(--bn-hue, var(--pt-mute)) 45%, transparent);
  }
  .twf-bn-btn .twf-bn-icon svg { stroke: currentColor; }
  .twf-bn-btn.active .twf-bn-icon { color: var(--bn-hue, var(--twf-nav-active)); }
  .twf-bn-btn.active::before { background: var(--bn-hue, currentColor); }
}

/* ── Command's seven-day strip ───────────────────────────────────────
   Seven numbers under seven day names. Was a white card holding seven
   tinted boxes; now seven quiet cells on the canvas, the busy days a little
   darker - brightness for state, the same rule as everything else. */
.twf-cmd-week {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 6px;
  margin: 0 0 18px;
}
.twf-cmd-day {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  padding: 10px 0 12px;
  border-radius: 10px;
  background: rgba(12, 18, 32, .03);
}
.twf-cmd-day .d {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .6px;
  text-transform: uppercase;
  color: var(--pt-mute, rgba(12, 18, 32, .45));
}
.twf-cmd-day .n {
  font-size: 17px;
  font-weight: 700;
  color: rgba(12, 18, 32, .3);
  font-variant-numeric: tabular-nums;
}
.twf-cmd-day.is-on  { background: rgba(201, 168, 76, .12); }
.twf-cmd-day.is-on  .n { color: var(--pt-navy, #0C1220); }
.twf-cmd-day.is-busy { background: rgba(201, 168, 76, .22); }
.twf-cmd-day.is-busy .n { color: var(--pt-navy, #0C1220); }

/* ── Stat tile sub-label (Command's "All cleared" / "Need staffing") ── */
.twf-pt-stat .k .s { display: block; margin-top: 2px; color: var(--pt-faint, rgba(12, 18, 32, .4)); }

/* A rail inside a flat accordion header (the Playbook) takes the same box
   the homepage rows use, so the two lists read as one family. */
.twf-flat .accordion-header .rail {
  width: 36px;
  height: 36px;
  border-radius: 10px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

/* ── Today's identity block ──────────────────────────────────────────
   Name and pins on one line, pins optically aligned to the text baseline
   rather than the box - which is what made them read as an eyebrow
   floating above the name instead of belonging to it. */

/* The pins sit on their own line under the name, flush left with it. */
.twf-today-pins {
  display: block;
  line-height: 0;
  margin-top: 6px;
}

/* "Add a photo" is a real button now, so it needs to stop looking like one
   in the browser's default sense and go back to looking like the quiet link
   it was drawn as. */
.twf-today-txt .cta {
  border: 0;
  background: none;
  padding: 0;
  font: inherit;
  cursor: pointer;
  text-align: left;
}

.twf-today-txt .cta:focus-visible {
  outline: 2px solid var(--pt-gold, #C9A84C);
  outline-offset: 2px;
  border-radius: 4px;
}

/* ── The Related strip ───────────────────────────────────────────────
   Was a white box of beige emoji pills at the top of the handbook and the
   hours tracker. Now a label and text links, on the canvas, with registry
   icons carrying the stroke. Wraps on a phone; each link keeps 44px. */

.twf-related {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0 18px;
  margin: 0 0 12px;
  padding: 0 2px;
}

/* The label takes its own line. Inline, it shared the first row with one
   link and pushed the rest to a second - a ragged split on every phone. */
.twf-related-k {
  flex: 0 0 100%;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: rgba(12, 18, 32, .45);
  margin-bottom: 2px;
}


.twf-related-link {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 44px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--pt-gold-strong, #A8852A);
  font: inherit;
  font-size: 15px;
  font-weight: 600;
  cursor: pointer;
  border-radius: 8px;
}

.twf-related-link .twf-i { stroke-width: 2.2; }

.twf-related-link:hover { color: var(--pt-navy, #0C1220); }

.twf-related-link:focus-visible {
  outline: 2px solid var(--pt-gold, #C9A84C);
  outline-offset: 2px;
}

/* ── Progress toward the next pin ────────────────────────────────────
   The one line on Today for the days nothing is booked. Quiet by design:
   it is a standing fact, not an alert. The bar is the only place in the
   app where gold means "you", rather than "the brand". */

.twf-pin-prog {
  padding: 4px 2px 18px;
  margin: 0 0 4px;
}

.twf-pin-prog-t {
  font-size: 15px;
  font-weight: 700;
  color: var(--pt-navy, #0C1220);
  letter-spacing: -0.01em;
}

.twf-pin-bar {
  position: relative;
  height: 6px;
  margin: 8px 0 6px;
  border-radius: 999px;
  background: rgba(12, 18, 32, .07);
  overflow: hidden;
}

.twf-pin-bar > span {
  position: absolute;
  left: 0; top: 0; bottom: 0;
  border-radius: 999px;
  background: var(--pt-gold, #C9A84C);
  transition: width .4s cubic-bezier(.4, 0, .2, 1);
}

.twf-pin-prog-b {
  font-size: 13px;
  color: var(--pt-mute, rgba(12, 18, 32, .55));
  font-variant-numeric: tabular-nums;
}

@media (prefers-reduced-motion: reduce) {
  .twf-pin-bar > span { transition: none; }
}

/* ── Today's zero state ──────────────────────────────────────────────
   Replaces the four stat tiles when every count is 0. Not a card: it sits
   on the canvas like the rest of Today. One title, one line, one action. */

.twf-pt-zero {
  padding: 8px 2px 18px;
  margin: 0 0 14px;
}

.twf-pt-zero-t {
  font-size: 17px;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--pt-navy, #0C1220);
}

.twf-pt-zero-b {
  font-size: 15px;
  line-height: 1.5;
  color: var(--pt-mute, rgba(12, 18, 32, .55));
  margin-top: 4px;
}

.twf-pt-zero-cta {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  margin-top: 12px;
  padding: 0 18px;
  border: 0;
  border-radius: 10px;
  background: var(--pt-gold, #C9A84C);
  color: var(--pt-navy, #0C1220);
  font: inherit;
  font-size: 15px;
  font-weight: 700;
  cursor: pointer;
}

.twf-pt-zero-cta:focus-visible {
  outline: 2px solid var(--pt-gold, #C9A84C);
  outline-offset: 2px;
}

/* ── The empty state, everywhere ─────────────────────────────────────
   twfEmptyState() is called from 17 screens (swap approvals, shift
   history, cover board, fill-in...). It drew a centred white card with a
   gold circle, a display-serif heading, and gold-filled CTA blocks - the
   loudest thing on a screen whose whole message is "nothing here".

   Same shape as Today's zero state now: left-aligned text on the canvas,
   and the CTAs become the same flat rows as everything else. One override,
   17 screens. The markup did not change. */

html body .twf-empty-state-v2 {
  text-align: left;
  padding: 8px 2px 18px;
  border: 0;
  border-radius: 0;
  background: none;
  box-shadow: none;
}

html body .twf-empty-state-v2 .twf-empty-icon { display: none; }

html body .twf-empty-state-v2 h3 {
  font-family: inherit;
  font-size: 17px;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--pt-navy, #0C1220);
  margin: 0;
}

html body .twf-empty-state-v2 p {
  font-size: 15px;
  line-height: 1.5;
  color: var(--pt-mute, rgba(12, 18, 32, .55));
  margin: 4px 0 6px;
  max-width: none;
}

html body .twf-empty-state-v2 .twf-empty-ctas {
  display: block;
  max-width: none;
  margin: 0;
}

html body .twf-empty-cta {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  min-height: 56px;
  padding: 12px 0;
  border: 0;
  border-radius: 0;
  background: none;
  box-shadow: none;
  color: var(--pt-navy, #0C1220);
  cursor: pointer;
}

html body .twf-empty-cta::after {
  content: "\203A";
  margin-left: auto;
  color: rgba(12, 18, 32, .32);
  font-size: 20px;
  line-height: 1;
}

html body .twf-empty-cta-icon {
  width: 40px;
  height: 40px;
  border-radius: 12px;
  background: rgba(201, 168, 76, .12);
  color: var(--pt-gold-strong, #A8852A);
}

html body .twf-empty-cta-title { font-size: 15px; font-weight: 600; }
html body .twf-empty-cta-sub { font-size: 13px; }

/* ── The cover board ─────────────────────────────────────────────────
   Each cover request was a white card. Now a block of text on the canvas,
   18px rhythm, with its Claim button inline. */

.twf-cover-list { display: block; }
.twf-cover-item { padding: 18px 2px; }
.twf-cover-item + .twf-cover-item { padding-top: 0; }

/* ── The list itself ─────────────────────────────────────────────────
   NO rule between rows. None.

   The first version of this kept a 1px hairline between items - a box
   around each replaced by a line between each. That is still a drawn break
   on every row, and it was still the thing that made the page feel ruled
   and heavy. .twf-pt-row on the homepage is border:0 and nothing else;
   the rows are held apart by space and by the left rail, not by lines.

   Invisible means invisible. */

.twf-flat .accordion-item {
  border: 0;
  border-radius: 0;
  margin-bottom: 0;
  background: none;
  overflow: visible;
}

/* ── The row ─────────────────────────────────────────────────────────
   Edge to edge, no fill. 56px min so it clears the 44px tap target with
   room to breathe - the homepage rows are 12px vertical padding on a
   ~20px line, which lands in the same place. */

/* With no rules between rows, space does the separating - so it gets more
   of it. 18px vertical (the rhythm bans 17 and 22) on a 15px line reads as
   distinct items without anything being drawn. */
.twf-flat .accordion-header {
  background: none;
  padding: 18px 2px;
  min-height: 56px;
  gap: 14px;
  font-size: 15px;
  font-weight: 600;
  letter-spacing: -0.01em;
  align-items: center;
}

.twf-flat .accordion-header > span:first-child {
  line-height: 1.35;
}

.twf-flat .accordion-item.open .accordion-header {
  color: var(--pt-gold-strong, #A8852A);
}

/* Keyboard focus has to survive losing the box. */
.twf-flat .accordion-header:focus-visible {
  outline: 2px solid var(--pt-gold, #C9A84C);
  outline-offset: 2px;
  border-radius: 6px;
}

/* ── The chevron ─────────────────────────────────────────────────────
   The markup ships a ▼ character. Rotating a glyph is not the same as a
   drawn chevron, so it is scaled down, muted, and turned 90 degrees to
   point right when closed - the iOS convention for "there is more here" -
   then down when open. */

.twf-flat .accordion-header .chevron {
  font-size: 11px;
  color: rgba(12, 18, 32, .32);
  transform: rotate(-90deg);
  transition: transform .22s cubic-bezier(.4, 0, .2, 1), color .2s;
  flex-shrink: 0;
  line-height: 1;
}

.twf-flat .accordion-item.open .chevron {
  transform: rotate(0deg);
  color: var(--pt-gold-strong, #A8852A);
}

/* ── The opened body ─────────────────────────────────────────────────
   No grey fill. The answer is just text under its question, indented
   enough to read as subordinate without a box drawing the relationship. */

.twf-flat .accordion-body {
  background: none;
}

.twf-flat .accordion-content {
  padding: 0 2px 18px;
  font-size: 14px;
  line-height: 1.65;
  color: var(--pt-ink-soft, rgba(12, 18, 32, .74));
}

.twf-flat .accordion-content p:last-child,
.twf-flat .accordion-content ul:last-child { margin-bottom: 0; }

/* ── Section headers ─────────────────────────────────────────────────
   The 2px gold rule under every section title was doing the work of
   separating content that the hairlines now do. Reduced to a label: small,
   uppercase, tracked - the same treatment the homepage uses above "This
   week" and "Waiting on you". */

.twf-flat .twf-hb-section-header {
  margin: 30px 0 4px;
  padding-bottom: 0;
  border-bottom: 0;
}

.twf-flat .twf-hb-section-header > div {
  font-family: var(--font-body), system-ui, sans-serif;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: rgba(12, 18, 32, .45);
}

/* The first section should not push a big gap under the page title. */
.twf-flat .twf-hb-section-header:first-of-type { margin-top: 12px; }

.twf-flat .twf-hb-intro {
  padding: 0 2px 6px;
  margin: 0 0 8px;
  font-size: 15px;
  line-height: 1.6;
  color: var(--pt-ink-soft, rgba(12, 18, 32, .74));
}
.twf-flat .twf-hb-intro p { margin: 0 0 10px; }
.twf-flat .twf-hb-intro p:last-child { margin-bottom: 0; }

/* ═══════════════════════════════════════════════════════════════════
   CHAT ON THE FLAT SYSTEM
   ═══════════════════════════════════════════════════════════════════
   2026-09-07. twf-chat.js carried 111 box constructs and zero flat rows -
   the conversation list had been rebuilt on the iMessage pattern back on
   09-04, but every sheet and modal around it was still hand-styled.

   43 of those constructs were in one function. The new-channel modal drew
   a centred card on a blurred dark backdrop and pasted the same
   180-character pill style eight times for eight preset buttons.

   These classes are the small amount of CSS the rebuild needs that the
   system did not already have. Everything else it uses - .twf-su,
   .twf-pt-row, .twf-pt-sh, .twf-seg, .rail, .twf-su-in, .twf-su-go - was
   already there and unreferenced by this file.
   ═══════════════════════════════════════════════════════════════════ */

/* The sheet host. A full-bleed canvas surface rather than a card floating
   on a dark scrim: the system has no cards, so a modal cannot be one. */
.twf-ch-sheet {
  position: fixed;
  inset: 0;
  z-index: 9999;
  background: var(--pt-canvas, #F4F6FB);
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  animation: twfChSheetIn .22s cubic-bezier(.32, .72, 0, 1);
}

@keyframes twfChSheetIn {
  from { opacity: 0; transform: translateY(12px); }
  to   { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .twf-ch-sheet { animation: none; }
}

/* Selection is the row tinting, not a control beside the name. The input
   still exists and still carries the value - createChatChannel reads
   .channel-member-cb:checked, and the broadcast submit reads the radio - it
   is simply not the thing you look at.

   .twf-pick is the shared behaviour: any flat row holding a hidden checkbox
   or radio. Written once here rather than per screen, because the second
   place that needed it turned up ten minutes after the first. */
.twf-pt-row.twf-pick { cursor: pointer; border-radius: 12px; padding-left: 8px; padding-right: 8px; }
.twf-pt-row.twf-pick > input[type="checkbox"],
.twf-pt-row.twf-pick > input[type="radio"] {
  position: absolute;
  opacity: 0;
  width: 1px;
  height: 1px;
  pointer-events: none;
}
.twf-pt-row.twf-pick:has(> input:checked) { background: var(--pt-info-bg, rgba(37, 99, 235, .10)); }
.twf-pt-row.twf-pick .twf-ch-tick {
  flex-shrink: 0;
  padding-right: 4px;
  font-size: 17px;
  color: var(--pt-info, #2563EB);
  opacity: 0;
  transition: opacity .12s ease;
}
.twf-pt-row.twf-pick:has(> input:checked) .twf-ch-tick { opacity: 1; }

/* :has() is iOS 15.4+. Below that the tick and tint never appear, so the
   control comes back rather than leaving selection invisible. */
@supports not selector(:has(*)) {
  .twf-pt-row.twf-pick > input[type="checkbox"],
  .twf-pt-row.twf-pick > input[type="radio"] {
    position: static;
    opacity: 1;
    width: 20px;
    height: 20px;
    accent-color: var(--pt-gold, #C9A84C);
    pointer-events: auto;
  }
  .twf-pt-row.twf-pick .twf-ch-tick { display: none; }
}

/* Audience picker: the same row, two up. */
.twf-ch-aud { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 4px; }
.twf-ch-aud .twf-pt-row { padding-top: 10px; padding-bottom: 10px; }
.twf-ch-aud .twf-pt-row .l1 { font-size: 13px; }

.twf-ch-filters { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }

/* A field keeps its edge - a select with no border is not a select - but it
   sits on the canvas and is 44px so a thumb can hit it. */
.twf-ch-sel {
  width: 100%;
  min-height: 44px;
  padding: 0 10px;
  font: inherit;
  font-size: 15px;
  color: var(--pt-ink, #0C1220);
  background: #fff;
  border: 1px solid var(--pt-line, rgba(12, 18, 32, .12));
  border-radius: 12px;
  box-sizing: border-box;
}

.twf-pt-sh.twf-ch-people { justify-content: space-between; }
.twf-pt-sh.twf-ch-people #chSelectedCount {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  color: var(--pt-gold-strong, #A8852A);
}

.twf-ch-bulk { display: flex; gap: 6px; padding: 0 0 6px; }
.twf-ch-bulk .twf-seg-btn { background: rgba(12, 18, 32, .05); border-radius: 8px; }

/* The sheet's own footer, sticky to the bottom so Create is reachable
   without scrolling a 30-person list to the end. */
.twf-ch-foot {
  position: sticky;
  bottom: 0;
  display: flex;
  gap: 8px;
  padding: 12px 0 max(12px, env(safe-area-inset-bottom));
  background: linear-gradient(to top, var(--pt-canvas, #F4F6FB) 62%, rgba(244, 246, 251, 0));
}
.twf-ch-cancel {
  min-height: 52px;
  padding: 0 18px;
  border: 0;
  border-radius: 14px;
  background: rgba(12, 18, 32, .06);
  color: var(--pt-ink, #0C1220);
  font: inherit;
  font-size: 15px;
  font-weight: 700;
  cursor: pointer;
}

/* Inline validation. Red text on the canvas, not a red box: the system draws
   nothing, and an error is not the one place to make an exception. */
.twf-inline-err {
  display: none;
  margin-top: 10px;
  padding: 0 2px;
  color: var(--pt-late, #B3261E);
  font-size: 13px;
  font-weight: 600;
  line-height: 1.45;
}

/* Thread replies. The body scrolls, the composer sits in the sticky footer
   the sheet already provides. */
.twf-ch-thread-body { display: flex; flex-direction: column; gap: 6px; padding: 4px 0 8px; }
.twf-ch-reply {
  flex: 1;
  min-width: 0;
  min-height: 52px;
  max-height: 120px;
  padding: 14px;
  line-height: 1.4;
  resize: none;
}

/* ═══════════════════════════════════════════════════════════════════
   PRESENCE AND FACES
   ═══════════════════════════════════════════════════════════════════
   2026-09-07. 2 of 59 active staff have a headshot, so a messaging list
   today is 57 sets of initials and 2 faces. The code was always ready for
   photos; nobody has uploaded one. That is a first-run prompt, not a
   feature - but the avatar has to be right for the day it changes.

   The dot means active in the last five minutes and nothing else. There is
   deliberately no "last seen 3 hours ago" anywhere in this app: the dot
   answers "can I reach them", a timestamp answers "what were you doing at
   eleven at night", and the second question is not one a staffing app
   should help anyone ask.
   ═══════════════════════════════════════════════════════════════════ */

.rail.twf-av { position: relative; overflow: visible; }
.rail.twf-av img {
  width: 100%;
  height: 100%;
  border-radius: inherit;
  object-fit: cover;
  display: block;
}
.rail.twf-av { font-size: 13px; font-weight: 700; letter-spacing: .02em; }

.rail.twf-av.is-active::after {
  content: "";
  position: absolute;
  right: -2px;
  bottom: -2px;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--pt-ok, #2E7D52);
  /* The ring is the canvas colour, not white, so the dot reads as cut out of
     the page rather than stuck on top of the avatar. */
  box-shadow: 0 0 0 2.5px var(--pt-canvas, #F4F6FB);
}

/* Presence is colour-only, which fails for anyone who cannot see the green.
   The name carries a screen-reader-only "(active now)" alongside it. */
.twf-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;
}

.twf-pt-row.twf-dm-picker-row { cursor: pointer; border-radius: 12px; padding-left: 8px; padding-right: 8px; }
.twf-pt-row.twf-dm-picker-row:active { background: rgba(12, 18, 32, .04); }

/* ── Faces, at the size a phone draws them ───────────────────────────
   The conversation list already used 48px; the picker was on the generic
   40px flat-row rail. Messaging is where faces earn their keep, so both
   sit at 48 and only there - Today's rows stay 40, because a rail carrying
   an icon is not a portrait. */
.twf-pt-row.twf-dm-picker-row .rail.twf-av {
  width: 48px;
  height: 48px;
  border-radius: 16px;
  font-size: 15px;
}
.twf-pt-row.twf-dm-picker-row .rail.twf-av.is-active::after {
  width: 13px;
  height: 13px;
  right: -1px;
  bottom: -1px;
}
.twf-pt-row.twf-dm-picker-row .l1 { font-size: 15px; }
.twf-pt-row.twf-dm-picker-row .l2 { font-size: 13px; }

/* A group is the people in it. Three faces, overlapping, first on top. */
.twf-gstack {
  display: inline-flex;
  align-items: center;
  flex-shrink: 0;
  width: 48px;
  height: 48px;
  padding-left: 6px;
}
.twf-gstack .twf-gf {
  position: relative;
  width: 30px;
  height: 30px;
  margin-left: -10px;
  border-radius: 10px;
  background: rgba(12, 18, 32, .06);
  color: var(--pt-navy, #0C1220);
  font-size: 11px;
  font-weight: 700;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  /* Cut out of the canvas, so the overlap reads as depth rather than mud. */
  box-shadow: 0 0 0 2px var(--pt-canvas, #F4F6FB);
}
.twf-gstack .twf-gf:first-child { margin-left: 0; }
.twf-gstack .twf-gf img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* An action attached to a message. Sits under the bubble like a Messages
   rich-link tap target, navy on the canvas so it reads as the one thing to
   do without becoming a second bubble. */
.twf-msg-action {
  margin-top: 6px;
  min-height: 40px;
  padding: 0 16px;
  border: 0;
  border-radius: 14px;
  background: var(--pt-navy, #0C1220);
  color: #fff;
  font: inherit;
  font-size: 14px;
  font-weight: 700;
  cursor: pointer;
  align-self: flex-start;
  -webkit-tap-highlight-color: transparent;
}
.twf-msg-action:active { opacity: .85; }

/* ── The clock ───────────────────────────────────────────────────────
   2026-09-08. The one surface on the Clock screen that earns being drawn:
   it is the reason people open it, and it gets read at arm's length in a
   loading dock with a tray in one hand.

   Navy, because a number that large on the canvas would fight Today for
   the top of the screen. Everything else on this screen is a row. */
.twf-clock {
  background: var(--pt-navy, #0C1220);
  border-radius: 20px;
  padding: 22px 20px 18px;
  margin: 4px 0 18px;
  text-align: center;
}
.twf-clock-t {
  font-size: 46px;
  font-weight: 700;
  line-height: 1;
  letter-spacing: 1px;
  color: var(--pt-gold, #C9A84C);
  font-variant-numeric: tabular-nums;
}
.twf-clock-d {
  margin-top: 8px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: rgba(255, 255, 255, .62);
}
@media (max-width: 380px) { .twf-clock-t { font-size: 38px; } }

/* ── Review detail ───────────────────────────────────────────────────
   2026-09-08. A review is richer than a row: it carries what went well,
   what did not, coaching, and a manager's note. That hangs under the row,
   indented to the rail's width so it reads as belonging to it, in the
   second-line voice rather than as a card of its own. */
.twf-rv-detail {
  padding: 0 4px 14px 52px;
  margin-top: -6px;
  font-size: 13px;
  line-height: 1.5;
  color: var(--pt-mute, rgba(12, 18, 32, .55));
}
.twf-rv-detail > div + div { margin-top: 4px; }
.twf-rv-good { color: var(--pt-ok, #2E7D52); }
.twf-rv-bad { color: var(--pt-late, #B3261E); }
.twf-rv-line strong { color: var(--pt-navy, #0C1220); font-weight: 700; }
.twf-rv-note {
  padding-left: 10px;
  border-left: 2px solid rgba(12, 18, 32, .12);
  border-radius: 0;
  font-style: italic;
}

/* A count, where a chevron would be on a row that does not navigate. */
.twf-rv-count {
  flex-shrink: 0;
  min-width: 26px;
  height: 22px;
  padding: 0 8px;
  border-radius: 999px;
  background: var(--pt-navy, #0C1220);
  color: #fff;
  font-size: 11px;
  font-weight: 700;
  line-height: 22px;
  text-align: center;
}

/* ── Availability ────────────────────────────────────────────────────
   2026-09-08. A day is a label and three choices. Written as a row so it
   sits in the same rhythm as everything else, but the three chips get the
   full width underneath rather than being squeezed beside the name - on a
   390px screen "Afternoon" does not fit next to "Wednesday". */
.twf-av-day { padding: 10px 2px 12px; }
.twf-av-dayname {
  font-size: 13px;
  font-weight: 700;
  color: var(--pt-navy, #0C1220);
  margin-bottom: 8px;
}
.twf-seg.twf-av-slots { display: flex; width: 100%; }
.twf-seg.twf-av-slots .twf-seg-btn { flex: 1; min-height: 40px; }

/* The picked-role detail: confidence and a note, indented to the rail. */
.twf-av-detail { padding: 2px 4px 14px 52px; }
.twf-av-detail .twf-seg { width: 100%; }
.twf-av-detail .twf-seg .twf-seg-btn { flex: 1; }
.twf-av-detail .avail-notes { min-height: 44px; font-size: 15px; }

/* The role row has no chevron, so the tick needs the trailing space. */
.avail-role-card .twf-pt-row { padding-top: 10px; padding-bottom: 10px; }

/* ============================================================================
   FORM PRIMITIVES  (2026-09-08)
   ----------------------------------------------------------------------------
   The review form had sixteen inline style strings repeated up to ten times
   each: ten section wrappers drawing a bordered panel, twenty inputs each
   restating the same border and radius, and eighteen labels restating the
   same 13px. 55KB of markup, most of it the same six declarations typed out
   again.

   These are those declarations, named. Nothing here is new design - it is the
   flat system's own tokens applied to the controls that were still styling
   themselves.

   .twf-fsec   a section. No fill, no border, no shadow. The heading and the
               space around it do the grouping, the way every other screen
               does it since the boxes came off.
   .twf-fl     a field label.
   .twf-fi     input, select and textarea. One edge, because a field you type
               into has to show you where it is - that is the exception the
               flat pattern always made for controls.
   ========================================================================= */
.twf-fsec { padding: 4px 0 18px; }
.twf-fsec + .twf-fsec { border-top: 1px solid var(--pt-line); padding-top: 16px; }
.twf-fsec-h { font-size: 11px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase;
  color: var(--pt-mute); margin: 0 0 12px; }
.twf-fsec-sub { font-size: 12px; color: var(--pt-faint); margin: -8px 0 12px; line-height: 1.4; }

.twf-fld { margin-bottom: 14px; }
.twf-fl { display: block; font-size: 13px; font-weight: 600; color: var(--pt-ink); margin-bottom: 6px; }
.twf-fl .opt { margin-left: 6px; font-size: 12px; font-weight: 500; color: var(--pt-faint); }

.twf-fi { width: 100%; box-sizing: border-box; min-height: 48px; padding: 12px 14px;
  border: 1.5px solid var(--pt-line); border-radius: var(--radius-lg); background: #fff;
  color: var(--pt-ink); font-size: 16px; font-family: inherit; }
textarea.twf-fi { min-height: 88px; resize: vertical; line-height: 1.45; }
.twf-fi:focus { outline: none; border-color: var(--pt-info-stripe); box-shadow: 0 0 0 3px var(--pt-info-bg); }
.twf-fi:disabled { background: var(--pt-canvas); color: var(--pt-faint); }

/* A row of tick boxes or radios. Same picked-tint behaviour as .twf-pick. */
.twf-fchk { display: flex; align-items: center; gap: 10px; min-height: 44px; cursor: pointer;
  user-select: none; font-size: 15px; color: var(--pt-ink); padding: 0 4px; border-radius: 10px; }
.twf-fchk input { width: 20px; height: 20px; flex-shrink: 0; accent-color: var(--pt-navy); }
.twf-fchk .sub { display: block; font-size: 12px; color: var(--pt-faint); margin-top: 1px; }
@supports selector(:has(*)) {
  .twf-fchk:has(input:checked) { background: var(--pt-info-bg); }
}
.twf-fchk-grid { display: flex; flex-wrap: wrap; gap: 4px 16px; }

/* The five review paths. One choice, so they read as one control. */
.twf-fpath { display: flex; flex-direction: column; }
.twf-fpath .twf-fchk { padding: 6px 8px; }

/* The tappable star row. NOT .twf-stars - that is the small inline glyph run
   in twf-styles-cockpit.css, and reusing the name would have shrunk these to
   1px gaps and pulled them off the baseline. */
.twf-star-row { display: flex; gap: 4px; align-items: center; }
.twf-star-row .star-btn { min-width: 44px; min-height: 44px; }

/* ============================================================================
   NOTIFICATIONS  (2026-09-08)
   The row and its acknowledge button are siblings, not nested. They used to
   be a <button> inside a <button>, which is invalid and needed a data-stop
   to keep the outer one from firing.
   ========================================================================= */
.twf-nt { display: flex; align-items: stretch; gap: 8px; }
.twf-nt-main { flex: 1; min-width: 0; }
.twf-nt-meta { display: flex; align-items: center; gap: 8px; margin-top: 4px; flex-wrap: wrap; }
.twf-nt-ago { font-size: 11px; color: var(--pt-faint); }
.twf-nt-ack { align-self: center; min-width: 56px; min-height: 44px; padding: 0 12px;
  border: 0; background: none; color: var(--pt-info); font-size: 13px; font-weight: 700;
  font-family: inherit; cursor: pointer; border-radius: 12px; flex-shrink: 0; }
.twf-nt-ack:hover { background: var(--pt-info-bg); }
.twf-nt-ack:disabled { color: var(--pt-ok); cursor: default; background: none; }
/* The count inside a segmented tab. Blank when the bucket is empty. */
.twf-nt-n { font-variant-numeric: tabular-nums; }
.twf-nt-n:not(:empty) { margin-left: 6px; color: var(--pt-faint); font-weight: 700; }
.twf-seg-btn.active .twf-nt-n:not(:empty) { color: inherit; }
.twf-nt-checked { font-size: 12px; color: var(--pt-faint); line-height: 1.6; padding: 0 2px 8px; }

/* ── Notifications that carry weight (2026-09-09) ─────────────────────
   Daryan: "notifications in the app should look and feel more assertive
   and stronger."

   They read like a log: 13px lines, faint timestamps, everything the same
   size whether it was a badge someone sent or a shift starting in an hour.
   A list where nothing is louder than anything else asks the reader to do
   the triage, every time, and the reliable outcome is that they stop
   opening it.

   Three changes, no new colours:
     - the headline is 16px and 700, so it is a statement and not a row
     - unread carries a solid gold bar and real weight; read recedes
     - anything requiring an answer keeps a live left edge until answered

   The palette is unchanged: this is weight and space doing the work. */
#notifDropdown .twf-nt { padding-top: 14px; padding-bottom: 14px; }
/* 17 and 15, on the scale. The first draft used 16 and 14, which are not
   steps - the scale is 11/12/13/15/17/20/26/34/72. type-scale.test.js only
   reads twf-styles-cockpit.css, so nothing would have caught these two here;
   they are on the scale because the scale is the point, not because a test
   made them. */
#notifDropdown .twf-nt .l1,
#notifDropdown .twf-nt-main > :first-child {
  font-size: 17px; font-weight: 700; line-height: 1.3;
  letter-spacing: -.15px; color: var(--pt-ink, #0C1220);
}
#notifDropdown .twf-nt-main .l2 { font-size: 15px; line-height: 1.45; color: var(--pt-sub, #5A6478); }
#notifDropdown .twf-nt-ago { font-size: 12px; font-weight: 600; color: var(--pt-sub, #5A6478); }

/* Unread is a state you can see from arm's length, not a tint you squint at. */
#notifDropdown .twf-nt.is-unread,
#notifDropdown .twf-nt[data-unread="1"] {
  box-shadow: inset 3px 0 0 0 var(--pt-gold, #C9A84C);
  padding-left: 11px;
  background: rgba(201, 168, 76, .05);
}
#notifDropdown .twf-nt.is-read .l1,
#notifDropdown .twf-nt[data-unread="0"] .l1 { font-weight: 600; color: var(--pt-sub, #5A6478); }

/* Something is waiting on you. Stays lit until it is answered. */
#notifDropdown .twf-nt[data-priority="action"],
#notifDropdown .twf-nt[data-priority="critical"] {
  box-shadow: inset 3px 0 0 0 var(--pt-late, #B91C1C);
  padding-left: 11px;
}

/* The sheet's own header, so the count is the first thing read. */
#notifDropdown .twf-nt-head { padding: 4px 2px 10px; }
/* 20, not 22. Third off-scale value I reached for in one sitting - 14, then
   16, then this - and all three were even numbers on a scale that runs
   11/12/13/15/17/20/26/34/72. The habit is reaching for a round number
   instead of the next step up. A sheet header is 20; 26 is a page title. */
#notifDropdown .twf-nt-head h2 { font-size: 20px; font-weight: 700; letter-spacing: -.3px; margin: 0; }

/* ============================================================================
   THE RATING STARS  (2026-09-08)
   ----------------------------------------------------------------------------
   These were <span>&#9733;</span> - a text glyph at font-size:32px, greyed to
   #ccc, with the selected state painted by setStarRating writing
   star.style.color inline.
   Three things wrong with that on a control a manager uses to score a person:
   a span is not reachable by keyboard and has no focus ring, the glyph
   renders differently on every platform and counted 99 times against the
   emoji ratchet in one form, and inline colour is the one thing the design
   system says an active state must never be.
   Drawn star from the registry, real button, 44px target, class-driven fill.
   ========================================================================= */
.star-btn { display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; padding: 0; border: 0; background: none; cursor: pointer;
  color: var(--pt-line); border-radius: 12px; -webkit-tap-highlight-color: transparent;
  transition: color .12s ease, transform .08s ease; }
.star-btn svg { width: 26px; height: 26px; fill: none; stroke: currentColor; stroke-width: 2; }
.star-btn.is-on { color: var(--pt-gold, #C9A84C); }
.star-btn.is-on svg { fill: currentColor; }
.star-btn:active { transform: scale(.92); }
.star-btn:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--pt-info-bg); }
.star-label { font-size: 13px; font-weight: 700; color: var(--pt-ink); margin-left: 8px; }

/* The pin on My Ratings. Centred, because on this screen the mark is the
   subject rather than a detail beside a name. */
.twf-rv-pins { display: flex; justify-content: center; padding: 6px 0 14px; }

/* ============================================================================
   TURN ON NOTIFICATIONS  (2026-09-08)
   ----------------------------------------------------------------------------
   The one screen in the app that is allowed to be loud. Everything else is
   flat rows on a canvas; this one has a hero, because it is the difference
   between a shift offer reaching somebody and a shift offer sitting in a
   database until the event is over.
   ========================================================================= */
.twf-push-hero { text-align: center; padding: 26px 18px 22px; margin: 4px 0 18px;
  border-radius: 22px; background: var(--pt-canvas); }
.twf-push-hero.is-on   { background: var(--pt-ok-bg); }
.twf-push-hero.is-todo { background: var(--pt-info-bg); }
.twf-push-hero.is-off  { background: var(--pt-late-bg); }
.twf-push-mark { display: inline-flex; align-items: center; justify-content: center;
  width: 72px; height: 72px; border-radius: 24px; background: #fff; margin-bottom: 14px; }
.twf-push-hero.is-on   .twf-push-mark { color: var(--pt-ok); }
.twf-push-hero.is-todo .twf-push-mark { color: var(--pt-info); }
.twf-push-hero.is-off  .twf-push-mark { color: var(--pt-late); }
.twf-push-mark svg { width: 40px; height: 40px; }
.twf-push-hero-t { font-size: 24px; font-weight: 800; line-height: 1.2;
  letter-spacing: -.3px; color: var(--pt-ink); margin-bottom: 8px; }
.twf-push-hero-s { font-size: 15px; line-height: 1.5; color: var(--pt-mute);
  max-width: 34ch; margin: 0 auto; }

/* The steps. Numbered, large, one instruction per line - this is read by
   somebody holding the phone they are being told to change. */
.twf-push-steps { list-style: none; counter-reset: twfstep; margin: 0; padding: 0; }
.twf-push-steps li { counter-increment: twfstep; position: relative;
  padding: 12px 0 12px 52px; min-height: 44px; }
.twf-push-steps li::before { content: counter(twfstep); position: absolute; left: 0; top: 10px;
  width: 34px; height: 34px; border-radius: 12px; background: var(--pt-navy); color: #fff;
  font-size: 16px; font-weight: 800; display: flex; align-items: center; justify-content: center; }
.twf-push-steps li b { display: block; font-size: 17px; font-weight: 700;
  color: var(--pt-ink); line-height: 1.3; }
.twf-push-steps li span { display: block; font-size: 14px; color: var(--pt-mute);
  line-height: 1.45; margin-top: 3px; }
.twf-push-steps-p { font-size: 16px; line-height: 1.55; color: var(--pt-ink); padding: 2px 2px 14px; }
.twf-push-note { text-align: center; font-size: 14px; color: var(--pt-mute); padding: 10px 12px 4px; }

/* The nudge that carries this screen everywhere else. */
.twf-push-nudge .l1 { color: var(--pt-late); }

/* ═══════════════════════════════════════════════════════════════
   PASSWORD FIELD: REVEAL + LIVE REQUIREMENT CHECKLIST
   2026-09-08 (M2)

   The wall people could not get through. The rule was stated once in 13px
   grey above the field, checked properly only on the server, and reported
   one failure at a time after a network round trip. On a phone, blind,
   between service, that is four or five attempts before somebody stops.

   Two additions. Show, because typing fourteen characters twice without
   seeing them is the actual failure. And a checklist that answers while
   they type rather than after they submit.
   ═══════════════════════════════════════════════════════════════ */

.twf-pwfield { position: relative; }

/* Sits inside the field's right edge. 44px tall so it is a real target, and
   padded off the edge so it never collides with the iOS strong-password key
   or a browser reveal control. */
.twf-pwreveal {
  position: absolute;
  right: 6px;
  top: 50%;
  transform: translateY(-50%);
  min-height: 44px;
  padding: 0 12px;
  background: none;
  border: 0;
  font: 600 13px/1 var(--font-body, 'DM Sans', sans-serif);
  color: var(--text-muted, #717378);
  cursor: pointer;
  border-radius: 8px;
}
.twf-pwreveal:hover { color: var(--navy, #0C1220); }
.twf-pwreveal:focus-visible { outline: 2px solid var(--gold, #C9A84C); outline-offset: 2px; }
.twf-pwreveal[aria-pressed="true"] { color: var(--navy, #0C1220); }

/* Room for the button so a long password never runs underneath it. */
.twf-pwfield .login-field { padding-right: 72px; }

/* No box. The checklist is text under a field, in the same flat idiom as
   every other list in the app - the rule reads as guidance, not as a second
   form the person has to fill in. */
.twf-pwmeter {
  margin: -6px 0 14px;
  text-align: left;
}

.twf-pwreq {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--text-muted, #717378);
  padding: 3px 0;
}
.twf-pwreq b { font-weight: 600; color: var(--navy, #0C1220); }

.twf-pwreq-mk {
  flex: 0 0 14px;
  text-align: center;
  font-weight: 700;
  line-height: 1.5;
}

/* Green only on satisfied. A checklist that is green before you have done
   anything teaches people to stop reading it. */
.twf-pwreq.is-on { color: var(--green, #2e7d32); }
.twf-pwreq.is-on b { color: inherit; }
.twf-pwreq.is-bad { color: var(--red, #c62828); }

/* ═══════════════════════════════════════════════════════════════
   STAFF HOME: THE STANDING LINE
   2026-09-08 (L4)

   Replaces a 24px-padded navy gradient card carrying a 44px glow-shadowed
   star glyph, the person's name at 28px, and a "Next Milestone" column.

   Standing is one fact. It does not need a billboard, and the name was
   already at the top of the screen in the header - the card printed it a
   second time, larger, twelve pixels below.

   Three stars and a label. Unrated shows three hollow ones and says "Not yet
   rated", because an absent rating is not a low rating.
   ═══════════════════════════════════════════════════════════════ */
.twf-hs-standing {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 2px 0 16px;
}
.twf-hs-stars { display: inline-flex; gap: 3px; line-height: 0; }
.twf-hs-star { color: rgba(12, 18, 32, .18); display: inline-flex; }
.twf-hs-star svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 2; }
.twf-hs-star.is-on { color: var(--pt-gold, #C9A84C); }
.twf-hs-t {
  font-size: 13.5px;
  font-weight: 600;
  color: var(--pt-mute, #63604F);
}

/* ═══════════════════════════════════════════════════════════════
   THE SHIFT CHECK-IN WIZARD
   2026-09-08 (L4)

   Four screens a person runs at the top of every shift, often standing in a
   loading dock on a phone. Was eight drawn boxes: 2px-bordered event cards,
   bordered role buttons, a green-washed notice panel and bordered Back
   buttons. Rows and shelves now, same as everywhere else.
   ═══════════════════════════════════════════════════════════════ */
.twf-wz-head { padding: 2px 0 14px; }
.twf-wz-step {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: var(--pt-faint, rgba(12, 18, 32, .4));
  margin-bottom: 6px;
}
.twf-wz-h { font-size: 24px; line-height: 1.15; margin: 0 0 4px; color: var(--pt-navy, #0C1220); }
.twf-wz-sub { font-size: 14px; line-height: 1.5; margin: 0; color: var(--pt-mute, #63604F); }

.twf-wz-checks { margin: 4px 0 18px; }

/* A checkbox row is a target, not a tick with a caption beside it. 52px so a
   gloved thumb finds it. */
.twf-fchk--two label { align-items: flex-start; }
.twf-fchk--two span { display: block; }
.twf-fchk--two b {
  display: block;
  font-size: 14.5px;
  font-weight: 600;
  color: var(--pt-navy, #0C1220);
}
.twf-fchk--two em {
  display: block;
  margin-top: 2px;
  font-size: 12.5px;
  font-style: normal;
  line-height: 1.45;
  color: var(--pt-mute, #63604F);
}

/* ── Standing, as a one-line subtitle on a person's row ──────────────────
   2026-09-08. Position is not identity here: we cross-train and people work
   whatever the night needs. What was under names before this was a job title
   - "Banquet Server" as a pill in the directory, "role · venue" in the
   teammate picker, "name · Server" in the rate-your-crew list.
   Standing is the thing a person earned and keeps. */
.twf-std { display: inline-flex; align-items: center; gap: 2px; vertical-align: middle; }
.twf-std-s { display: inline-flex; color: rgba(12, 18, 32, .20); }
.twf-std-s svg { width: 12px; height: 12px; fill: none; stroke: currentColor; stroke-width: 2.2; }
.twf-std-s.is-on { color: var(--pt-gold, #C9A84C); }
.twf-std--new {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .3px;
  color: var(--pt-faint, rgba(12, 18, 32, .42));
}

/* ── Settings, Security: the inline result messages ──────────────────────
   2026-09-08. Were two always-present divs toggled with style.display, both
   drawing a filled box. Hidden by default via a class now, so a re-render
   cannot leave one showing, and flat like everything else. */
.twf-pw-msg { display: none; margin: 0 0 14px; font-size: 13.5px; line-height: 1.55; }
.twf-pw-msg.is-shown { display: block; }
.twf-pw-msg.is-bad { color: var(--pt-late, #9a1c1c); }
.twf-pw-msg.is-ok  { color: var(--pt-ok, #2e7d32); }

/* ── Hands up ──────────────────────────────────────────────────
   The screen where a manager commits a person to a night's work.
   It replaced a three-column grid inside a 1100px container whose
   third column - the Confirm button - collapsed to about forty
   pixels on a phone. The decision is the most consequential one a
   manager makes in this app and it was the hardest thing in it to
   tap. Everything here is sized for a thumb in a loading dock. */
.twf-hu { padding: 0 0 96px; }
.twf-hu-head { padding: 20px 16px 4px; }
.twf-hu-head h2 { font-size: 26px; line-height: 1.15; font-weight: 700; color: var(--pt-ink, #0C1220); margin: 0; }
.twf-hu-head p { font-size: 14px; line-height: 1.45; color: var(--pt-sub, #5A6478); margin: 6px 0 0; max-width: 46ch; }

.twf-hu-ev { margin-top: 18px; }
.twf-hu-evh {
  display: flex; align-items: center; gap: 12px; width: 100%;
  padding: 14px 16px; background: none; border: 0; border-top: 1px solid var(--pt-line, rgba(12,18,32,.08));
  text-align: left; cursor: pointer; font: inherit; color: inherit;
}
.twf-hu-evh .m { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.twf-hu-evh .l1 { font-size: 17px; font-weight: 700; color: var(--pt-ink, #0C1220); }
.twf-hu-evh .l2 { font-size: 13px; color: var(--pt-sub, #5A6478); }
.twf-hu-evh .chev { color: var(--pt-sub, #5A6478); font-size: 20px; }
.twf-hu-evh:active { background: rgba(12, 18, 32, .04); }

.twf-hu-why { padding: 0 16px 8px; font-size: 12px; line-height: 1.45; color: var(--pt-sub, #5A6478); }

/* The row is tall on purpose. A name, what they have earned, and why
   they sit where they sit - then one control that is impossible to miss. */
.twf-hu-row { align-items: center; min-height: 76px; padding-top: 12px; padding-bottom: 12px; }
.twf-hu-row .m { gap: 3px; }
.twf-hu-row .l3 { font-size: 12px; line-height: 1.4; color: var(--pt-sub, #5A6478); }
.twf-hu-row .twf-hu-flag { color: var(--pt-warn, #B45309); font-weight: 600; }
.twf-hu-row.is-on .l1 { color: var(--pt-sub, #5A6478); }
.twf-hu-row .rail.r-person { font-size: 13px; font-weight: 700; letter-spacing: .02em; }

.twf-hu-yes {
  flex-shrink: 0; min-height: 44px; min-width: 116px; padding: 0 18px;
  background: var(--pt-gold, #C9A84C); color: #0C1220;
  border: 0; border-radius: 12px; font-size: 15px; font-weight: 700; cursor: pointer;
}
.twf-hu-yes:active { transform: scale(.97); }
.twf-hu-yes:focus-visible { outline: 2px solid var(--pt-ink, #0C1220); outline-offset: 2px; }

@media (max-width: 400px) {
  .twf-hu-yes { min-width: 92px; padding: 0 12px; font-size: 14px; }
}
