/* The frame only: the bands the shell owns, plus the stand-ins it falls back to
   when a design component has not landed. The design lane owns the reset, the
   type and every color; everything here reads a token first and a brand default
   only as a guard, so design/*.css always wins. */

:root {
  /* The green bar grows to the act it is naming, so the room the screen keeps
     for it is the bar's own measurement (design/components.js publishes
     --bar-h-real) and only falls back to the token before the first paint.
     Neither number carries the safe area: every rule below adds that itself. */
  --shell-bar-h: var(--bar-h-real, var(--bar-h, 88px));
  /* The whole room the welded bar takes, safe area and all. The design system
     owns the number (--bar-room in design/components.css); this is the guard
     for the moment before that stylesheet has landed. One number, so nothing
     in the frame can reserve 88px for a bar that grew to 114. */
  --shell-bar-room: var(--bar-room, calc(var(--shell-bar-h) + env(safe-area-inset-bottom, 0px)));
  /* What the row DRAWS, not what it was meant to: 6 + 56 + 6 of button and padding, and 1 of rule.
     It said 64 for a long time and every rule that stands on the row was 5 short. design.test.js
     adds the row up from this stylesheet and fails when the two part company again. */
  --shell-tabs-h: 69px;
  --shell-gutter: var(--gutter, 24px);
  /* Room for an undo toast, which is a control and may not be hung over one.
     Nought until a toast is up; then it is the height the toast MEASURED
     (design/components.js publishes --toast-h-real the way it publishes
     --bar-h-real) plus the gap it stands on. That gap is --s4 and not a number
     typed here: the toast layer stands itself off the bands by --s4 (see
     design/components.css .toasts), and while this said 12px the room was four
     pixels short of the standoff, so elementsFromPoint on the room iPad still
     found the bottom edge of chair 3 and chair 4 under the toast. */
  --shell-toast-room: 0px;
}
body[data-toast="on"] { --shell-toast-room: calc(var(--toast-h-real, 68px) + var(--s4, 16px)); }

body {
  background: var(--c-paper, #FCFBF7);
  /* The frame is exactly the glass and the SCREEN is what scrolls (see #screen).
     Without this the page keeps a scrollbar of its own on the difference between
     100vh and 100dvh and the whole frame slides under the notch. */
  overflow: hidden;
}
/* THE DOCUMENT IS EXACTLY THE GLASS TOO. base.css still reserves the welded bar on
   the BODY, from the days when the page was the scroller. The frame reserves every
   band on #chrome now, so that padding only made the document 88px taller than the
   glass it lives in: overflow:hidden stops a finger, but not a scrollIntoView that
   reaches the viewport, and one of those would slide the whole frame up and take
   the head row and the outage banner off the top with it. */
body[data-greenbar="on"] { padding-bottom: 0; }

/* THE FLOW STOPS WHERE THE WELDED BANDS BEGIN.
   The tab row, the green bar and an undo toast are painted over the glass, so the
   frame's own column ends above them: its bottom padding IS their room. That is
   what makes "no control is ever under another control" structural instead of a
   rule five stylesheets have to remember. Every one of these reads the one number
   for the bar (--shell-bar-room, the measured bar plus the home indicator) and the
   one number for a toast (--shell-toast-room, nought until one is up). */
#chrome {
  display: flex;
  flex-direction: column;
  height: 100vh;
  height: 100dvh;   /* an iPad with the bar showing is shorter than 100vh */
  padding: env(safe-area-inset-top, 0px) env(safe-area-inset-right, 0px) 0 env(safe-area-inset-left, 0px);
  padding-bottom: calc(env(safe-area-inset-bottom, 0px) + var(--shell-toast-room));
}
#chrome[data-tabs="yes"] { padding-bottom: calc(var(--shell-tabs-h) + env(safe-area-inset-bottom, 0px) + var(--shell-toast-room)); }
body[data-greenbar="on"] #chrome { padding-bottom: calc(var(--shell-bar-room) + var(--shell-toast-room)); }
body[data-greenbar="on"] #chrome[data-tabs="yes"] {
  padding-bottom: calc(var(--shell-bar-room) + var(--shell-tabs-h) + var(--shell-toast-room));
}

/* One line, at the top, that names whose fault an outage is. */
#banner {
  padding: 10px var(--shell-gutter);
  background: var(--fill-due, #F6EDDA);
  border-bottom: 1px solid var(--line-due, #E0C489);
  color: var(--c-amber-text, #8A5D20);
  font-size: var(--t-label, .94rem);
  font-weight: 700;
}

/* THE HEAD ROW. The frame's own row, between the bands that report an outage and
   the screen that scrolls. It exists for the one control that has to be reachable
   from every screen, so when that control is away (the sign-in wall, the rest
   board) the row is away with it rather than leaving a band of blank paper. */
#head {
  display: flex; align-items: center; justify-content: flex-end;
  gap: var(--s2, 8px);
  padding: 8px var(--shell-gutter) 0;
}
#head[hidden] { display: none; }

/* GET HELP. One control, the same place on every screen, in the frame's head row
   and never over the screen's own paper. It is deliberately small and quiet: it is
   never the act a screen is asking for, and it is never further away than one tap.
   It was position:fixed for four walks and every list scrolled under it. */
#help {
  display: inline-flex; align-items: center; gap: 8px;
  min-height: 44px; padding: 0 14px 0 10px;
  border: 1.5px solid var(--c-hair, #E4E7DE); border-radius: 999px;
  background: var(--c-card, #FFFFFF); color: var(--c-mark, #0B361B);
  font: inherit; font-size: var(--t-label, .94rem); font-weight: 700;
  box-shadow: 0 1px 2px rgba(30, 43, 37, .06);
  cursor: pointer;
}
#help[hidden] { display: none; }
#help:active { background: var(--c-mist, #EEF2EB); }
/* No band arithmetic. Every band the frame owns is a row in the same column, so a
   banner or a did not send strip pushes this row down by being there. The sum of
   three band heights typed into a stylesheet was always one combination short. */
@media (max-width: 599px) {
  #help { padding: 0 12px 0 8px; font-size: var(--t-fine, .82rem); }
}

/* NEEDS YOU. The notices waiting for whoever is signed in here. A picture, one
   neutral sentence and a count, in the flow above the screen. It is deliberately
   not amber and never red: nothing in it is wrong, these are things waiting.
   The outage banner and the did not send strip are the two amber bands, and a
   third one stacked under them would make all three invisible. */
#needs {
  display: flex; align-items: center; gap: 10px;
  width: 100%; min-height: 60px;
  padding: 8px var(--shell-gutter);
  border: 0; border-bottom: 1px solid var(--c-hair, #E4E7DE);
  background: var(--c-mist, #EEF2EB); color: var(--c-ink, #1E2B25);
  font: inherit; text-align: left; cursor: pointer;
}
#needs[hidden] { display: none; }
#needs:active { background: color-mix(in srgb, var(--c-mark, #0B361B) 10%, var(--c-mist, #EEF2EB)); }
#needs .needs-pic { line-height: 0; flex: none; color: var(--c-mark, #0B361B); }
.needs-word { font-weight: 700; flex: none; color: var(--c-mark, #0B361B); }
/* One sentence. A second one belongs behind the tap, not in the frame. */
.needs-line {
  flex: 1 1 auto; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  color: var(--c-ink70, rgba(30,43,37,.74)); font-size: var(--t-label, .94rem);
}
.needs-count {
  flex: none; min-width: 32px; height: 32px; padding: 0 10px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--r-pill, 999px);
  background: var(--c-forest, #0B361B); color: var(--c-on-forest, #FCFBF7);
  font-variant-numeric: tabular-nums; font-weight: 700; font-size: var(--t-label, .94rem);
}
/* Something interruptive is waiting. One hairline of amber, and nothing else:
   the buzz already happened in the person's pocket. */
#needs[data-loud="yes"] { border-bottom-color: var(--line-due, #E0C489); box-shadow: inset 0 -2px 0 var(--line-due, #E0C489); }

/* The list behind it. One line per notice, one act on each. */
.needs-list { display: grid; gap: var(--s3, 12px); }
.needs-item {
  display: flex; align-items: center; gap: var(--s3, 12px);
  min-height: 76px; padding: var(--s3, 12px) var(--s4, 16px);
  border: 1.5px solid var(--c-hair, #E4E7DE); border-radius: var(--r-tile, 14px);
  background: var(--c-card, #FFFFFF);
}
.needs-item .plate { flex: none; color: var(--c-mark, #0B361B); }
.needs-item-main { flex: 1 1 auto; min-width: 0; display: grid; gap: 2px; }
.needs-item-word { font-weight: 700; }
.needs-item-line { color: var(--c-ink70, rgba(30,43,37,.74)); font-size: var(--t-label, .94rem); }
.needs-item[data-loud="yes"] { border-left: 2px solid var(--c-amber-text, #8A5D20); }
.needs-got {
  flex: none; display: inline-flex; align-items: center; gap: 8px;
  min-height: var(--touch-min, 44px); padding: 0 18px;
  border: 1.5px solid var(--c-mark, #0B361B); border-radius: var(--r-pill, 999px);
  background: var(--c-forest, #0B361B); color: var(--c-on-forest, #FCFBF7);
  font: inherit; font-weight: 700; cursor: pointer;
}
.needs-got .plate, .needs-got .shape { color: var(--c-on-forest, #FCFBF7); }
/* Forest fill, so the forest ring base.css draws would be invisible on it. The
   same rule the design layer applies to every other act that fills with forest. */
.needs-got:focus-visible { outline-color: var(--c-on-forest, #FCFBF7); }
.needs-got[disabled] { opacity: .5; }
.needs-more { margin: 0; color: var(--c-ink70, rgba(30,43,37,.74)); font-size: var(--t-label, .94rem); }
.needs-clear { display: grid; justify-items: center; gap: var(--s3, 12px); padding: var(--s5, 24px) 0; text-align: center; color: var(--c-mark, #0B361B); }
.needs-clear-word { margin: 0; font-family: var(--font-serif, Georgia, serif); font-size: var(--t-h3, 1.25rem); }
.needs-clear-line { margin: 0; color: var(--c-ink70, rgba(30,43,37,.74)); font-size: var(--t-label, .94rem); }
/* A phone has no room for a sentence beside a word and a pill, so the count
   stays on the first line where the word is and the sentence takes the second
   one whole. */
@media (max-width: 599px) {
  #needs { flex-wrap: wrap; row-gap: 2px; padding-block: 10px; min-height: 72px; }
  .needs-count { order: 1; margin-left: auto; }
  .needs-line { order: 2; flex: 1 0 100%; white-space: normal; }
  .needs-item { flex-wrap: wrap; row-gap: var(--s2, 8px); }
  .needs-got { flex: 1 0 100%; justify-content: center; }
}

/* Writes the server refused for good. Calm, in the flow, with the count in words. */
#notsent {
  display: flex; align-items: center; gap: 10px;
  width: 100%; min-height: 56px;
  padding: 8px var(--shell-gutter);
  border: 0; border-bottom: 1px solid var(--line-due, #E0C489);
  background: var(--fill-due, #F6EDDA); color: var(--c-amber-text, #8A5D20);
  font: inherit; text-align: left; cursor: pointer;
}
#notsent[hidden] { display: none; }
.notsent-word { font-weight: 700; }
.notsent-fact { color: var(--c-ink70, rgba(30,43,37,.74)); font-size: var(--t-label, .94rem); }

/* What the frame says when it refuses a tap. It sits where the tab row is, because
   the tab row is what it is about, and it goes away by itself. */
#said {
  position: fixed; left: 50%; transform: translateX(-50%);
  bottom: calc(var(--shell-tabs-h) + 12px + env(safe-area-inset-bottom, 0px));
  z-index: 45;
  display: grid; gap: 2px; justify-items: center;
  max-width: min(520px, calc(100% - 2 * var(--shell-gutter)));
  margin: 0; padding: 12px 18px;
  border-radius: var(--r-tile, 14px);
  background: var(--c-toast, #1E2B25); color: var(--c-on-toast, #FCFBF7);
  font-size: var(--t-body, 1.0625rem); text-align: center;
}
#said[hidden] { display: none; }
#said span { color: var(--c-on-toast-70, rgba(252,251,247,.78)); font-size: var(--t-label, .94rem); }
body[data-greenbar="on"] #said { bottom: calc(var(--shell-bar-room) + var(--shell-tabs-h) + 12px); }
#chrome[data-tabs="no"] #said { bottom: calc(24px + env(safe-area-inset-bottom, 0px)); }
body[data-greenbar="on"] #chrome[data-tabs="no"] #said { bottom: calc(var(--shell-bar-room) + 24px); }

/* The undo toast is built by the design layer and knows about the bar. It does not know this frame
   has a tab row, so inside the frame it stands on top of the row too: a toast that lands on
   "Today" is five seconds of navigation nobody can press.
   The standoff is --s4, the same token the design layer stands it off the bar with and the same
   one --shell-toast-room reserves, so the top of the toast and the bottom of the screen are the
   same pixel whichever bands are up. Typed numbers here drifted from the design layer's token
   and left a sliver of the board under a control. */
body:has(#chrome[data-tabs="yes"]) .toasts {
  bottom: calc(var(--shell-tabs-h) + var(--s4, 16px) + env(safe-area-inset-bottom, 0px));
}
body[data-greenbar="on"]:has(#chrome[data-tabs="yes"]) .toasts {
  bottom: calc(var(--shell-bar-room) + var(--shell-tabs-h) + var(--s4, 16px));
}

/* A screen in the middle of something unsaved holds the row. Dimmed, still there,
   and a tap on it says what to do instead of throwing the work away. */
#tabs[data-held="yes"] button { opacity: .45; }

/* The list behind the strip: one line per write, two acts, no path and no red. */
.notsent-list { display: grid; gap: var(--s3, 12px); }
.notsent-lead { margin: 0; color: var(--c-ink70, rgba(30,43,37,.74)); font-size: var(--t-label, .94rem); }
.notsent-item {
  display: grid; gap: 6px;
  padding: 14px;
  border: 1.5px solid var(--c-hair, #E4E7DE); border-radius: var(--r-tile, 14px);
  background: var(--c-card, #FFFFFF);
}
.notsent-item-word { font-weight: 700; color: var(--c-ink, #1E2B25); }
.notsent-item-fact { color: var(--c-ink70, rgba(30,43,37,.74)); font-size: var(--t-label, .94rem); }
.notsent-acts { display: flex; flex-wrap: wrap; gap: var(--s2, 8px); margin-top: 4px; }
.notsent-act {
  display: inline-flex; align-items: center; gap: 8px;
  min-height: 48px; padding: 0 16px;
  border: 1.5px solid var(--c-hair, #E4E7DE); border-radius: var(--r-tile, 14px);
  background: var(--c-paper, #FCFBF7); color: var(--c-ink, #1E2B25);
  font: inherit; font-size: var(--t-body, 1.0625rem); cursor: pointer;
}
.notsent-act:active { background: var(--c-mist, #EEF2EB); }
.notsent-clear { display: grid; justify-items: center; gap: var(--s3, 12px); padding: var(--s5, 24px) 0; color: var(--c-mark, #0B361B); }
.notsent-clear-word { margin: 0; font-family: var(--font-serif, Georgia, serif); font-size: var(--t-h3, 1.25rem); }

/* THE SCREEN IS THE SCROLLER. The page does not scroll; the screen scrolls inside
   the room the frame gives it, which is the glass less every band the frame owns.
   That is what makes the head row above it and the welded bands below it honest:
   the thing that moves ends where the things that stay begin. min-height:0 because
   a flex item's floor is its content, and without it a long board pushes the frame
   past the glass and takes the tab row with it. The bottom padding here is the
   breathing room under the last tile and nothing else: the bands are #chrome's. */
/* The frame moves focus here after a screen swap so the new screen is read from
   its own heading. It is a landmark and not a control, so it draws no ring of
   its own: nothing was aimed at, nothing was activated, and a 3px outline around
   the entire board would read as "this whole thing is selected". The first real
   control the person reaches still draws the product's one focus ring. */
#screen:focus, #screen:focus-visible,
#veil:focus, #veil:focus-visible { outline: none; }

#screen {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  padding: var(--shell-gutter);
  padding-bottom: 16px;
}

/* PAPER HAS NO SCROLLPORT. On the glass the screen is a box that scrolls inside
   the frame; on a page that box would print its first 700 points and drop the
   rest. Printing gives the flow back to the document, exactly as the sheet's own
   print rule gives it back to a sheet body. */
@media print {
  body { overflow: visible; }
  #chrome { height: auto; }
  #screen { overflow: visible; }
}

/* The quiet tab row sits ABOVE the green bar and never competes with it. */
#tabs {
  position: fixed;
  left: 0; right: 0;
  bottom: env(safe-area-inset-bottom, 0px);
  z-index: 30;
  display: flex;
  justify-content: center;
  gap: var(--s2, 8px);
  padding: 6px var(--shell-gutter);
  background: var(--c-paper, #FCFBF7);
  border-top: 1px solid var(--c-hair, #E4E7DE);
}
body[data-greenbar="on"] #tabs { bottom: var(--shell-bar-room); }
#tabs:empty { display: none; }
#tabs button {
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  min-width: 96px; min-height: 56px;
  border: 0; background: none; cursor: pointer;
  color: var(--c-ink70, rgba(30,43,37,.74));
  font: inherit; font-size: var(--t-fine, .82rem);
}
#tabs button[aria-current="page"] { color: var(--c-mark, #0B361B); font-weight: 700; }

/* Soft lock: the work behind this is untouched, it is only blurred. */
#veil {
  position: fixed; inset: 0; z-index: 50;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--s4, 16px);
  padding: var(--shell-gutter);
  background: color-mix(in srgb, var(--c-paper, #FCFBF7) 82%, transparent);
  backdrop-filter: blur(14px);
}
/* base.css turns every [hidden] off, and this is the one where getting it wrong costs
   the whole iPad: clearSoftLock() empties the veil, so without the rule the right PIN
   unlocks the session, the blur stays, and every tap after it lands on nothing. */
#veil[hidden] { display: none; }
/* inert on the bands does the real locking; this only makes it look locked. */
html[data-soft-lock="yes"] #screen,
html[data-soft-lock="yes"] #tabs,
html[data-soft-lock="yes"] #bar { pointer-events: none; }

.shell-head { font-family: var(--font-serif, Georgia, serif); color: var(--c-mark, #0B361B); }
.shell-note { color: var(--c-ink70, rgba(30,43,37,.74)); font-size: var(--t-label, .94rem); }
.shell-code {
  width: 100%; max-width: 420px; min-height: 72px;
  font-family: var(--font-mono, ui-monospace, monospace); font-size: 32px;
  letter-spacing: .25em; text-align: center; text-transform: uppercase;
  border: 1.5px solid var(--c-hair, #E4E7DE); border-radius: var(--r-input, 10px);
}
/* Sign in is the whole screen and nothing else, so it sits in the middle of it
   rather than pinned to the top with a lobby's worth of paper underneath. */
.signin {
  display: grid; gap: var(--s5, 24px); justify-items: center; align-content: center;
  padding-block: 0;
}
/* ONE RULE, because the screen is a box with a height of its own now. It is the
   glass minus the frame's bands, minus its own padding, and that padding is
   already the bar, the tab row and the home indicator: so 100% IS the room left
   to centre in, with the bar up or without it. It used to be two rules of
   viewport arithmetic, and the one that forgot a band welded the one field and
   the one heading to the top of an otherwise empty iPad. */
.signin { min-height: 100%; }
.signin > .shell-head { text-align: center; }
/* The way back off the PIN pad: a picture and a word, like every other button. */
.shell-back {
  display: inline-flex; align-items: center; gap: 8px;
  min-height: 56px; padding: 0 18px;
  border: 1.5px solid var(--c-hair, #E4E7DE); border-radius: var(--r-tile, 14px);
  background: var(--c-card, #FFFFFF); color: var(--c-ink, #1E2B25);
  font: inherit; font-size: var(--t-body, 1.0625rem); cursor: pointer;
}

/* -------- the quiet board: a lobby reads this all day, signed in to nothing -------- */
.rest {
  display: grid; justify-items: center; align-content: center; gap: var(--s6, 32px);
  /* One track, and it may never be wider than the glass. Without the explicit track an
     auto column is sized by the chair board's max-content, the board then lays four
     190px chairs out inside it whatever the iPad is, and in portrait the fourth chair
     hangs off the right edge of a screen a lobby reads all day. */
  grid-template-columns: minmax(0, 1fr);
  /* The screen is a box with a height of its own, so the room to centre in is all
     of it. The arithmetic version had to guess which bands were up. */
  min-height: 100%;
  text-align: center;
}
.rest-head { display: grid; justify-items: center; gap: var(--s4, 16px); }
.rest-mark { width: 56px; height: 56px; color: var(--c-mark, #0B361B); opacity: .9; }
.rest-clock {
  font-family: var(--font-mono, ui-monospace, monospace); font-variant-numeric: tabular-nums;
  font-size: clamp(3.5rem, 11vw, 7rem); font-weight: 300; line-height: 1;
  letter-spacing: -.045em; color: var(--c-ink, #1E2B25);
}
.rest .qboard { width: 100%; max-width: 900px; }
.rest-next { display: grid; justify-items: center; gap: var(--s3, 12px); }
.rest-next-word {
  font-size: var(--t-eyebrow, .72rem); font-weight: 700; letter-spacing: .15em;
  text-transform: uppercase; color: var(--c-ink70, rgba(30,43,37,.74));
}
.rest-next-row { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--s5, 24px); }
.rest-next-row b {
  font-family: var(--font-mono, ui-monospace, monospace); font-variant-numeric: tabular-nums;
  font-size: clamp(1.25rem, 3.4vw, 1.875rem); font-weight: 500; letter-spacing: -.01em;
  color: var(--c-ink70, rgba(30,43,37,.74));
}
.rest-way { width: 100%; max-width: 420px; border-top: 1px solid var(--c-hair, #E4E7DE); }
/* One way in, and it is the largest thing on the board after the clock. */
.rest .tilepad, .rest .stand-in-pad {
  grid-template-columns: minmax(0, max-content); justify-content: center;
}
.rest .tile, .rest .stand-in-tile { width: 300px; height: 188px; gap: var(--s3, 12px); }
.rest .tile .tile-word { font-size: var(--t-h3, 1.25rem); }
@media (max-width: 599px) {
  .rest { gap: var(--s5, 24px); align-content: start; padding-top: var(--s4, 16px); }
  .rest-mark { width: 40px; height: 40px; }
  .rest-way { max-width: 280px; }
  .rest .tile, .rest .stand-in-tile { width: 260px; height: 164px; }
}

/* -------- a screen that did not load: calm, and one way forward -------- */
.screenfault {
  display: grid; grid-template-columns: minmax(0, 1fr);
  justify-items: center; align-content: center; gap: var(--s5, 24px);
  min-height: 100%; text-align: center;
}
.screenfault h1 { color: var(--c-mark, #0B361B); }
.screenfault p { color: var(--c-ink70, rgba(30,43,37,.74)); }
/* One tile, under the middle of the sentence that explains it. A pad left to its own
   auto-fit columns parks the single way forward against the left margin. */
.screenfault .tilepad, .screenfault .stand-in-pad {
  grid-template-columns: minmax(0, max-content); justify-content: center;
}

/* -------- stand-ins, live only while a design component is missing -------- */
html[data-live="no"] .stand-in-tile,
html[data-live="no"] .stand-in-chair,
html[data-live="no"] .stand-in-row,
html[data-live="no"] .stand-in-stat { border-style: dashed; border-width: 1.5px; }
.stand-in-pad { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 12px; width: 100%; }
.stand-in-tile, .stand-in-chair, .stand-in-row, .stand-in-face {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px;
  min-height: 88px; padding: 12px;
  border: 1.5px solid var(--c-hair, #E4E7DE); border-radius: var(--r-tile, 14px);
  background: var(--c-card, #FFFFFF); color: var(--c-ink, #1E2B25);
  font: inherit; font-size: var(--t-body, 1.0625rem); cursor: pointer;
}
.stand-in-tile.is-lit { border-color: var(--c-mark, #0B361B); border-width: 2px; }
.stand-in-tile[disabled] { opacity: .45; cursor: default; }
.stand-in-word { font-weight: 600; }
.stand-in-fact, .stand-in-bar-fact { color: var(--c-ink70, rgba(30,43,37,.74)); }
.stand-in-bar {
  display: flex; flex-direction: column; align-items: flex-start; justify-content: center; gap: 2px;
  position: fixed; inset: auto 0 0 0; z-index: 40;
  width: 100%; min-height: var(--shell-bar-h);
  padding: 10px var(--shell-gutter) calc(10px + env(safe-area-inset-bottom, 0px));
  border: 0; background: var(--c-forest, #0B361B); color: var(--c-on-forest, #FCFBF7);
  font: inherit; font-size: var(--t-lead, 1.1875rem); text-align: left; cursor: pointer;
}
.stand-in-bar-word { font-weight: 700; }
.stand-in-bar-fact, .stand-in-bar-why { font-size: var(--t-fine, .82rem); }
.stand-in-ladder { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; width: 100%; }
.stand-in-rung { display: flex; align-items: center; gap: 10px; padding: 10px 12px; background: var(--c-card, #fff); }
.stand-in-rung.is-done { border-left: 2px solid var(--c-leaf, #346D35); color: var(--c-ink70, rgba(30,43,37,.74)); }
.stand-in-rung.is-missing { border-left: 2px solid var(--c-amber-text, #8A5D20); }
.stand-in-fix { margin-left: auto; min-height: 44px; padding: 0 14px; font: inherit; }
.stand-in-wall { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 12px; width: 100%; }
.stand-in-pinpad { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; max-width: 320px; }
.stand-in-dots { grid-column: 1 / -1; text-align: center; font-size: 28px; letter-spacing: .3em; }
.stand-in-key {
  min-height: 72px; font: inherit; font-size: 26px;
  background: var(--c-card, #fff); border: 1px solid var(--c-hair, #E4E7DE); border-radius: var(--r-tile, 14px);
}
.stand-in-mono { font-family: var(--font-mono, ui-monospace, monospace); font-variant-numeric: tabular-nums; }
.stand-in-sheet { position: fixed; inset: auto 0 0 0; padding: var(--shell-gutter); background: var(--c-card, #fff); z-index: 60; }
.stand-in-toast {
  position: fixed; left: 50%; transform: translateX(-50%);
  bottom: calc(var(--shell-bar-room) + 76px); z-index: 60;
  display: flex; gap: 12px; align-items: center; padding: 12px 16px;
  background: var(--c-toast, #1E2B25); color: var(--c-on-toast, #FCFBF7); border-radius: var(--r-tile, 14px);
}
.stand-in-stat { display: grid; gap: 4px; padding: 14px; border: 1.5px solid var(--c-hair, #E4E7DE); background: var(--c-card, #fff); }
.stand-in-stat-label { color: var(--c-amber-text, #8A5D20); font-size: var(--t-eyebrow, .72rem); text-transform: uppercase; letter-spacing: .06em; }
.stand-in-stat-value { font-family: var(--font-mono, ui-monospace, monospace); font-size: 30px; }
