/* Film Hub application stylesheet.
   Moved out of portal.php's inline <style> on September 6, 2026 (FH-20260906-035)
   so every application page shares one stylesheet governed by docs/DESIGN-SYSTEM.md.
   Load order (from _layout.php): fonts.css, design-tokens.css, filmhub-tokens.css,
   shared-layout.css, app.css, typography.css. */
:root {
  /* Legacy names used throughout this stylesheet, aliased onto filmhub-tokens.css.
     No color, size, radius, shadow or duration is written here (RULES F-018). */
  --cab-blue-deep: var(--cab-blue-dark);
  --cab-sky: var(--cab-blue-light);
  --cab-gold: var(--cab-yellow);
  --action: var(--action-primary);
  --action-hover: var(--action-primary-hover);
  --bg: var(--surface-page);
  --surface: var(--surface-card);
  --surface-tint: var(--surface-muted);
  --ink: var(--text-body);
  --ink-soft: var(--text-muted);
  --muted: var(--text-muted);
  --hairline: var(--border-subtle);
  --line: var(--border-subtle);
  --navy: var(--cab-blue-dark);
  --ok: var(--status-success-text);      --ok-bg: var(--status-success-bg);
  --info: var(--cab-blue-dark);               --info-bg: var(--status-info-bg);
  --warn: var(--status-attention-text);  --warn-bg: var(--status-attention-bg);
  --idle: var(--status-neutral-text);    --idle-bg: var(--status-neutral-bg);
  --radius: var(--radius-card);
  --shadow: var(--shadow-none);
  --font-body: var(--font-sans);
  --font-mono: var(--font-mono-brand);
}
* { margin: 0; padding: 0; box-sizing: border-box; }
html { font-size: 16px; }
body { font: 400 1rem/1.55 var(--font-body); background: var(--bg); color: var(--ink); -webkit-font-smoothing: antialiased; }
main { min-height: 62vh; }
.wrap { max-width: 1100px; margin: 0 auto; padding: 0 20px; }
main .wrap { padding-top: 32px; padding-bottom: 56px; }
html { min-height: 100%; }
body { min-height: 100dvh; display: flex; flex-direction: column; }
body > main { flex: 1 0 auto; }
.site-header, .site-footer { flex: none; }
/* Long panes were an endless scroll. Native <details> so each group can be
   folded away, keyboard-operable and with no state to keep in JS. */
/* Grid: many narrow columns, so the labels rotate and the first column
   stays put while you scroll sideways — the Gradebook pattern. */
table.grid { border-collapse: separate; border-spacing: 0; }
table.grid th, table.grid td { border-bottom: 1px solid var(--hairline); }
/* A static chip: a named document with its state, not a mark in a column
   whose heading was rotated ninety degrees and then clipped. */
.chip-static{display:inline-block;padding:5px 10px;margin:0 6px 6px 0;border-radius:999px;
  border:1px solid var(--hairline);background:var(--surface);font-size:.86rem;line-height:1.3}
.chip-static.g-ok{background:var(--ok-bg);color:var(--ok);border-color:transparent}
.chip-static.g-wait{background:var(--warn-bg);color:var(--warn);border-color:transparent}
.chip-static.g-warn{background:var(--warn-bg);color:var(--warn);border-color:var(--warn)}
.chip-static.g-waive{background:var(--idle-bg);color:var(--idle);border-color:transparent}
.chip-static.g-none{color:var(--muted)}
.g-stick { position: sticky; left: 0; background: var(--surface); z-index: 2; min-width: 190px; }
thead .g-stick { z-index: 3; }
.g-col { height: 132px; vertical-align: bottom; padding: 0 !important; width: 34px; }
.g-rot { display: block; writing-mode: vertical-rl; transform: rotate(180deg);
         white-space: nowrap; font: 600 .74rem/1 var(--font-body); color: var(--muted);
         padding: 8px 0; max-height: 124px; overflow: hidden; }
.g-cell { text-align: center; width: 34px; font-weight: 700; font-size: .9rem; }
.g-ok    { background: var(--ok-bg);   color: var(--ok); }
.g-wait  { background: var(--warn-bg); color: var(--warn); }
.g-waive { background: var(--idle-bg); color: var(--idle); }
.g-none  { background: var(--surface); }
.g-foot td { background: var(--surface-tint); font-weight: 700; color: var(--muted); }
.g-hot { color: var(--warn) !important; }
@media (prefers-reduced-motion: reduce) { .g-rot { transition: none; } }

.fold { border: 1px solid var(--hairline); border-radius: var(--radius);
        background: var(--surface); margin-bottom: 10px; overflow: hidden; }
.fold > summary {
  display: flex; align-items: center; gap: 12px; cursor: pointer; list-style: none;
  padding: 14px 16px; font: 700 1rem/1.2 var(--font-body); color: var(--cab-blue-dark);
  background: var(--surface);
}
.fold > summary::-webkit-details-marker { display: none; }
.fold > summary:hover { background: var(--surface-tint); }
.fold > summary::after {
  content: ""; margin-left: auto; flex: none; width: 8px; height: 8px;
  border-right: 2px solid var(--muted); border-bottom: 2px solid var(--muted);
  transform: rotate(45deg); transition: transform var(--dur-base) var(--ease-standard);
}
.fold[open] > summary::after { transform: rotate(-135deg); }
.fold[open] > summary { border-bottom: 1px solid var(--hairline); }
.fold__body { padding: 14px 16px 16px; }
.instruction-list{margin:0;padding-left:1.35rem;color:var(--muted);font-size:.92rem;line-height:1.6}
.instruction-list li+li{margin-top:.55rem}
.instruction-list a{color:var(--text-link);font-weight:600;text-decoration:underline;text-underline-offset:2px;overflow-wrap:anywhere}
.fold__count { font: 600 .72rem/1 var(--font-mono); letter-spacing: .08em;
               color: var(--muted); text-transform: uppercase; }
.fold__pill { font: 600 .68rem/1 var(--font-mono); padding: 4px 8px; border-radius: 99px;
              background: var(--surface-tint); color: var(--cab-blue-dark); }
.foldbar { display: flex; gap: 8px; margin-bottom: 12px; }
@media (prefers-reduced-motion: reduce) { .fold > summary::after { transition: none; } }

/* Phases. One course at a time, so the table stays the same width whether
   the program runs two courses or twenty. */
.phase-head { display: flex; align-items: flex-end; gap: 14px; flex-wrap: wrap; margin: 0 0 14px; }
.phase-pick { display: flex; flex-direction: column; gap: 4px; }
/* One control size. This used to restyle the select and leave the date
   input beside it on the base rule, so a Course box 40px tall with a 1px
   border sat next to a Date box 44px tall with a 1.5px one, their labels on
   different lines. Everything here now inherits the base control and only
   sets its width. */
.phase-pick { min-width: 170px; max-width: 230px; }
.phase-pick select, .phase-pick input { width: 100%; color: var(--cab-blue-dark); font-weight: 600; cursor: pointer; }
.phase-tally { font: .82rem/1.6 var(--font-body); color: var(--muted); align-self: center; }
.phase-tally b { font-family: var(--font-mono); font-size: .9rem; }
.pt-required { color: var(--cab-blue-dark); }
.pt-conditional { color: var(--warn); }
.pt-available { color: var(--ok); }
.pt-hidden { color: var(--muted); }

.phase-tbl td, .phase-tbl th { padding-top: 7px; padding-bottom: 7px; }
.phase-tbl .ph-tick { width: 34px; text-align: center; }
.phase-tbl .ph-tick input { width: 17px; height: 17px; cursor: pointer; accent-color: var(--cab-blue-dark); }
.phase-tbl .ph-fmt { width: 74px; }
.phase-tbl .ph-set { width: 148px; }
.phase-tbl .ph-req { width: 136px; }
.req-sel {
  font: 600 .74rem/1 var(--font-body); padding: 6px 8px; min-height: 30px; width: 100%;
  border: 1px solid var(--hairline); border-radius: var(--radius-sm); background: var(--surface);
  color: var(--cab-blue-dark); cursor: pointer;
}
.phase-tbl tr.ph-lit { background: var(--surface-tint); }

/* The state reads as a word, not only as a colour. Height matches the
   34 px control token (draft 10) rather than a size of its own. */
.st-sel {
  font: 600 .76rem/1 var(--font-body); padding: 7px 8px; min-height: var(--control-height); width: 100%;
  border-radius: var(--radius-sm); cursor: pointer; border: 1px solid transparent;
}
.st-required    { background: var(--cab-blue-dark); color: var(--cab-white); }
.st-conditional { background: var(--warn-bg); color: var(--warn); border-color: var(--warn); }
.st-available { background: var(--ok); color: var(--cab-white); }
.st-hidden    { background: var(--surface); color: var(--muted); border-color: var(--hairline); }

/* Only present while rows are ticked. A state control, not an action row
   (hard rule on actions, 2026-09-19, rule 6): hard-coded flex-wrap:nowrap
   above 720px so it never wraps or boxes its controls, and a readable
   column below it, the way an ordinary set of form fields is allowed to
   stack. Never scrolls sideways: everything either fits the row or drops
   to the column. */
.pickbar {
  position: sticky; bottom: 14px; z-index: 20;
  display: flex; align-items: flex-end; gap: 10px; flex-wrap: nowrap;
  background: var(--surface); border: 1px solid var(--cab-blue-dark); border-radius: var(--radius);
  box-shadow: var(--shadow); padding: 10px 14px; margin-top: 16px;
}
.pickbar__n { font: 600 .72rem/1.5 var(--font-mono); letter-spacing: .08em; text-transform: uppercase; color: var(--cab-blue-dark); flex: none; align-self: center; white-space: nowrap; }
/* Set to: label above field, matching the equipment-filter-field pattern
   used elsewhere in the portal. */
.pickbar__field { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1 1 150px; }
.pickbar__field label { display: block; margin: 0; font: 600 .68rem/1.3 var(--font-body); letter-spacing: .04em; text-transform: uppercase; color: var(--muted); }
.pickbar select {
  font: 600 .74rem/1 var(--font-body); padding: 6px 8px; min-height: var(--control-height); width: 100%;
  border: 1px solid var(--hairline); border-radius: var(--radius-sm); background: var(--surface);
  color: var(--cab-blue-dark); cursor: pointer; min-width: 0;
}
#pick-move { flex: 1 1 120px; width: auto; }
.pickbar > .btn { flex: none; white-space: nowrap; }
.pickbar__spacer { flex: 1 1 auto; min-width: 0; }
@media (max-width: 720px) {
  .pickbar { flex-direction: column; align-items: stretch; }
  .pickbar select { min-height: var(--control-height-phone); }
  .pickbar__field, #pick-move, .pickbar > .btn { flex: none; width: 100%; }
  .pickbar__spacer { display: none; }
}
.site-header { background: var(--cab-blue-dark); color: var(--cab-white); position: relative; }
/* Yellow keyline under the bar — the one flash of brand colour on an
   otherwise procedural screen. */
.header-link {
  color: var(--cab-white); font: 600 .82rem/1 var(--font-body); text-decoration: none;
  border-bottom: 1px solid rgba(255,255,255,.4); padding-bottom: 2px;
}
.header-link:hover { color: var(--cab-yellow); border-bottom-color: var(--cab-yellow); }
.site-header .wrap { display: flex; align-items: center; gap: 14px; padding-top: 14px; padding-bottom: 14px; flex-wrap: wrap; }
.portal-brand__name { font-weight: 700; font-size: 1.1rem; }
.portal-brand__name span { color: var(--cab-sky); font-weight: 400; }
.portal-header__spacer { flex: 1; }
.portal-header__back { margin-right: 14px; }
.portal-header__signout { margin-left: 6px; }
.brand { display: flex; align-items: baseline; gap: 10px; color: var(--cab-white); text-decoration: none; }
.brand .sub { font: 600 .72rem/1 var(--font-mono); letter-spacing: .14em; text-transform: uppercase; color: var(--cab-sky); }
.site-footer { border-top: 1px solid var(--hairline); background: var(--cab-blue-dark); color: var(--cab-white); margin-top: 56px; }
.site-footer .wrap { padding: 40px 20px 24px; }
.site-footer p { font-size: .85rem; margin: 0; }
.site-footer a { color: var(--cab-white); }
.site-footer a:hover { color: var(--cab-yellow); }
.foot-cols { display: grid; gap: 28px; grid-template-columns: minmax(220px, 1.4fr) repeat(2, minmax(140px, 1fr)); }
.foot-brand { font-weight: 700; font-size: 1rem; }
.foot-addr { color: rgba(255,255,255,.72); line-height: 1.6; margin-top: 8px !important; }
.foot-head { font: 600 .68rem/1 var(--font-mono); letter-spacing: .14em; text-transform: uppercase; color: var(--cab-sky); margin-bottom: 12px !important; }
.foot-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 9px; font-size: .9rem; }
.foot-base { margin-top: 30px; padding-top: 18px; border-top: 1px solid rgba(255,255,255,.18);
             display: flex; gap: 12px; flex-wrap: wrap; align-items: center; justify-content: space-between; }
.foot-base p { color: rgba(255,255,255,.6); font-size: .8rem; }
.foot-mark { font: 600 .8rem/1 var(--font-mono); letter-spacing: .14em; color: var(--cab-sky) !important; }
@media (max-width: 700px) { .foot-cols { grid-template-columns: 1fr 1fr; } .foot-cols > :first-child { grid-column: 1 / -1; } }
@media (max-width: 420px) { .foot-cols { grid-template-columns: 1fr; } }
h1 { font-size: 1.7rem; font-weight: 700; letter-spacing: -.015em; line-height: 1.15; color: var(--cab-blue-dark); }
h2 { font-size: 1.15rem; font-weight: 700; letter-spacing: -.01em; color: var(--cab-blue-dark); margin-bottom: 4px; }
h3 { font-size: .98rem; font-weight: 600; color: var(--ink); }
/* A card heading that is an h2 by rank but an h3 by eye. "Starting a new film?"
   sits between "Welcome" (h1) and "Documents" (h2), so as an h3 it skipped a
   level and left the outline reading h1 -> h3 -> h2. Screen readers navigate by
   that outline; the design wanted the smaller size. Both, rather than either. */
.card-h { font-size: .98rem; font-weight: 600; color: var(--ink); margin-bottom: 2px; letter-spacing: 0; }
/* Off-screen until focused, so a keyboard user can jump the header and nav
   instead of tabbing through them on every screen. Mirrors the public site. */
.skip { position: absolute; left: -9999px; top: 0; z-index: 100;
  background: var(--surface); color: var(--cab-blue-dark); padding: 12px 18px;
  border-radius: var(--radius-none); font-weight: 700; }
.skip:focus { left: 0; }
a { color: var(--text-link); text-underline-offset: 2px; transition: color var(--dur-fast) var(--ease-standard); }
a:hover { color: var(--text-link-hover); }
.cab-label { font: 600 .7rem/1.4 var(--font-mono); letter-spacing: .13em; text-transform: uppercase; color: var(--text-label); margin-bottom: 6px; }
.cab-caption { font: 500 .78rem/1.5 var(--font-mono); color: var(--muted); }
/* Readability is accessibility here: the instructor is dyslexic, and
   cramped or bunched text is a barrier, not a style choice. Secondary text
   keeps a full line height, rows breathe, and long text never runs edge to
   edge. Do not tighten these to fit more on screen. */
.cab-small { font-size: .85rem; color: var(--muted); line-height: 1.55; }
.th-sort { border: 0; background: none; padding: 0; cursor: pointer;
  font: 600 .68rem/1.4 var(--font-mono); letter-spacing: .09em; text-transform: uppercase;
  color: var(--muted); white-space: nowrap; }
.th-sort:hover { color: var(--cab-blue-dark); }
table.data thead th { cursor: pointer; }
table.data thead th:hover { color: var(--cab-blue-dark); }
table.data thead th.th-asc::after { content: " ▲"; }
table.data thead th.th-desc::after { content: " ▼"; }
/* Row actions stay reachable when the roster scrolls sideways. */
.roster-tbl th:last-child, .roster-tbl td:last-child {
  position: sticky; right: 0; background: var(--surface); border-left: 1px solid var(--hairline); }
.roster-tbl tbody tr:hover td:last-child { background: var(--surface-tint); }
.doc-row > span, .doc-row .grow { line-height: 1.55; }
.doc-row { row-gap: 6px; }
details > summary { line-height: 1.5; }
.card p, .fold__body p { line-height: 1.55; }
.num { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
/* No widows: table.data only protected its header cells from wrapping
   (th above), leaving a number cell, a caption, or a caption right after a
   pill free to break mid value. Also covers a date wrapped in .when inside
   prose (.im), so a checkout's "out" or "Returned" date and a production
   number sitting in a sentence hold together the same way a table cell
   already does. Deliberately narrow: .im itself and long text columns
   (Phases document titles) must keep wrapping. */
.num, .cab-caption, .when, .meta-unit, table.data td.num, .st + .cab-caption { white-space: nowrap; }
.meta-unit--wrap-text { white-space: normal; overflow-wrap: anywhere; }
.meta-unit--wrap-text .num { white-space: nowrap; overflow-wrap: normal; }
.btn { display: inline-flex; align-items: center; justify-content: center; gap: 6px; font: 500 13px/20px var(--font-body); letter-spacing: .01em; border-radius: var(--radius-pill); border: 1px solid transparent; padding: var(--control-pad); min-height: var(--control-height); width: auto; flex: none; white-space: nowrap; cursor: pointer; text-decoration: none; transition: background-color var(--dur-fast) var(--ease-standard), border-color var(--dur-fast) var(--ease-standard), color var(--dur-fast) var(--ease-standard), transform var(--dur-fast) var(--ease-standard); }
.btn:active { transform: translateY(var(--shift-press)); }
.btn-primary { background: var(--action); color: var(--cab-white); }
.btn-primary:hover { background: var(--action-hover); color: var(--cab-white); }
.btn-secondary { background: var(--cab-blue-dark); color: var(--cab-white); }
.btn-secondary:hover { background: var(--cab-blue-deep); color: var(--cab-white); }
.btn-ghost { background: var(--surface); color: var(--cab-blue-dark); border-color: var(--hairline); }
.btn-ghost:hover { border-color: var(--cab-blue); color: var(--cab-blue); }
/* Ghost pills on the Dark Blue header keep white text on a transparent fill; shared-layout.css sets the text white. */
.site-header .btn-ghost { background: transparent; color: var(--cab-white); border-color: rgba(255, 255, 255, .5); }
.site-header .btn-ghost:hover { background: rgba(255, 255, 255, .12); border-color: var(--cab-white); color: var(--cab-white); }
.btn-small { padding: var(--control-pad); min-height: var(--control-height); font-size: var(--type-support); }
.student-load-error{display:flex;align-items:center;gap:12px;margin-top:12px;padding:12px 14px;border:1px solid var(--hairline);border-radius:var(--radius);background:var(--surface-tint)}
.student-load-error p{margin:0;flex:1;color:var(--muted)}
.student-load-error .btn{flex:0 0 auto}
/* Only for a confirm that cannot be undone. It should not look like the
   button next to it. */
.btn-danger { background: var(--danger); color: var(--cab-white); }
.btn-danger:hover { background: var(--danger-hover); color: var(--cab-white); }
.btn[disabled] { opacity: .45; cursor: not-allowed; }
:focus-visible { outline: 2px solid var(--cab-blue-dark); outline-offset: 2px; }
.fh-app :is(a,button,select):focus-visible { box-shadow: none; outline: 2px solid var(--cab-blue-dark); outline-offset: 2px; }
.card { background: var(--surface); border: 1px solid var(--hairline); border-radius: var(--radius); box-shadow: var(--shadow); padding: 20px 22px; }
.card--tint { background: var(--surface-tint); border-color: transparent; box-shadow: none; }
.card--accent { background: var(--surface-tint); border-left: 4px solid var(--cab-blue); border-radius: var(--radius-card); }
.notice { background: var(--warn-bg); border-left: 4px solid var(--warn); border-radius:var(--radius-md); padding: 12px 16px; }
.kpi-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 12px; margin: 18px 0 22px; }
.kpi { background: var(--surface); border: 1px solid var(--hairline); border-radius: var(--radius); box-shadow: var(--shadow); padding: 14px 18px; }
.kpi .k-label { font: 600 .66rem/1.4 var(--font-mono); letter-spacing: .1em; text-transform: uppercase; color: var(--muted); }
.kpi .k-value { font: 700 1.7rem/1.2 var(--font-body); color: var(--cab-blue-dark); font-variant-numeric: tabular-nums; }
.kpi .k-sub { font-size: .78rem; color: var(--muted); }
.kpi.k-good .k-value { color: var(--ok); }
.kpi.k-warn .k-value { color: var(--warn); }
.st { display: inline-flex; align-items: center; gap: 5px; font: 500 12px/1 var(--font-body); min-height: 22px; border-radius: var(--radius-pill); padding: 2px 10px; white-space: nowrap; }
.st::before { font-weight: 700; }
.st-approved::before, .st-cleared::before { content: "\25CF"; }
.st-submitted::before, .st-none::before, .st-pending::before { content: "\25CB"; }
.st-revision_required::before { content: "!"; }
.st-approved, .st-cleared { background: var(--ok-bg); color: var(--ok); }
.st-submitted { background: var(--info-bg); color: var(--info); }
.st-revision_required { background: var(--warn-bg); color: var(--warn); }
.st-none, .st-pending { background: var(--idle-bg); color: var(--idle); }
/* Test lane badge (FH-20260919-TEST-LANE-001): quiet on purpose, since the
   switch that reveals it already tells the instructor what they are
   looking at. Reuses the idle tint rather than adding a new status color. */
.st-test::before { content: none; }
.st-test { background: var(--idle-bg); color: var(--muted); font-weight: 600; text-transform: uppercase; letter-spacing: .04em; font-size: 10.5px; min-height: 18px; padding: 1px 8px; }
.prog { height: 7px; border-radius: 99px; background: var(--idle-bg); overflow: hidden; }
.prog > span { display: block; height: 100%; border-radius: 99px; background: var(--cab-blue-dark); transition: width var(--dur-slow) var(--ease-standard); }
.prog.p-done > span { background: var(--ok); }
.tbl-wrap { overflow-x: auto; }
/* A library document read in place, inside a form or on the signing page. */
.doc-embed { margin: 0 0 12px; }
.doc-embed__frame { display: block; width: 100%; max-width: 100%; height: 60vh; min-height: 320px; border: 1px solid var(--hairline); border-radius: var(--radius); background: var(--surface); }
/* Inside a signing panel the embed is deliberately taller than the panel
   can show. Forms.gateOnReading holds the sign control until the panel has
   been scrolled past the whole agreement, and at 60vh the agreement already
   fitted on a desktop: measured live on the Volunteer Agreement, the embed
   ended 844px down a 1002px panel, so the gate unlocked before the student
   had touched anything. Taller than the panel means getting past it is
   always a real scroll. The panel is the only place a document is embedded
   above something to sign, so nothing else changes. */
.panel__body .doc-embed__frame { height: 105vh; }
/* The signature pad (FH-20260912-071): the same drawing surface sign.php's
   guest page uses, restyled with app.css tokens for use inside a panel. */
.sig-pad { position: relative; width: 100%; max-width: 100%; }
.sig-pad canvas { display: block; width: 100%; max-width: 100%; height: auto; aspect-ratio: 3 / 1; border: 1px solid var(--hairline); border-radius: var(--radius); background: var(--surface); touch-action: none; cursor: crosshair; }
.sig-pad__hint { position: absolute; left: 1rem; bottom: .75rem; color: var(--muted); font-size: .85rem; pointer-events: none; }
.sig-pad__hint.is-hidden { display: none; }
.sig-pad__tools { display: flex; justify-content: flex-end; margin: 8px 0 14px; }
.rel-qr svg { display: block; width: 100%; height: auto; }
/* Hard rule on actions, 19 Sep 2026: Copy and Open on this phone measured
   258px combined at 320px phone width with "Open on this phone" alone
   near 150px, more than the panel leaves for a shared row with the link
   field. The field is its own full-width line above (portal-student.php's
   companion instructor call and the student Rel.render both use it); this
   panel-actions-row holds only the two buttons, which fit one line at
   every width the hard rule measures. */
/* The Releases table sits in a 520px panel: the state's date goes under its
   pill so that column stays narrow. The action cell used to stack its own
   buttons (September 11) to avoid scrolling off the right edge; the hard
   rule on actions (19 Sep 2026) forbids a stacked action group even inside
   a table row, so the cell holds its own buttons on one line now and the
   table's existing .tbl-wrap scrolls sideways as a whole on narrow panels,
   the same fallback every other data table in the app already uses. */
.rel-table .st + .cab-caption { display: block; margin-top: 2px; }
.rel-table td:last-child { text-align: right; white-space: nowrap; }
.rel-table td:last-child .btn { display: inline-flex; margin: 0 0 0 8px; }
.rel-table td:last-child .btn:first-child { margin-left: 0; }
/* Measured on staging (September 11): four columns at the panel's 15px 16px cell padding came to 470px
   in a 453px wrap with TT Interphases loaded. Tighter cells bring the table to the wrap's width. */
.fh-app table.data.rel-table th, .fh-app table.data.rel-table td { padding: 12px 8px; }
.fh-app table.data.rel-table th:first-child, .fh-app table.data.rel-table td:first-child { padding-left: 0; }
.fh-app table.data.rel-table th:last-child, .fh-app table.data.rel-table td:last-child { padding-right: 0; }
table.data { width: 100%; border-collapse: collapse; font-size: .88rem; background: var(--surface); }
table.data th { text-align: left; padding: 10px 12px; font: 600 .68rem/1.4 var(--font-mono); letter-spacing: .09em; text-transform: uppercase; color: var(--muted); border-bottom: 2px solid var(--hairline); white-space: nowrap; }
table.data td { padding: 11px 12px; border-bottom: 1px solid var(--hairline); vertical-align: top; }
table.data tbody tr:hover { background: var(--surface-tint); }
table.data tbody tr:last-child td { border-bottom: none; }
label { display: block; font: 600 .78rem/1.5 var(--font-body); color: var(--ink); margin: 14px 0 4px; }
input[type=text], input[type=email], input[type=password], input[type=tel],
input[type=date], input[type=time], input[type=number], input[type=url], select, textarea {
  width: 100%; font: 400 1rem/1.4 var(--font-body); color: var(--ink);
  background: var(--surface); border: 1px solid var(--hairline); border-radius: var(--radius-sm);
  padding: 9px 12px; min-height: var(--field-height); transition: border-color var(--dur-fast) var(--ease-standard);
}
input:focus, select:focus, textarea:focus { border-color: var(--cab-blue-dark); outline: 2px solid var(--cab-blue-dark); outline-offset: 2px; box-shadow: none; }
textarea { min-height: 84px; resize: vertical; }
input[type=checkbox] { width: 20px; height: 20px; accent-color: var(--cab-blue-dark); cursor: pointer; }
/* A 1-10 rating slider (Forms.renderField's whole-field "scale" type and
   every "scale"-typed table column, crew_evaluation being the first form to
   use either). The readout is a real <output>, not a placeholder span, so
   it reads correctly to assistive tech and its own text never drops below
   the phone body-text floor. The track keeps a 44px tall hit area on phones
   (thumb plus generous vertical padding) even though the visible bar itself
   stays thin, matching the mobile rule's 44 by 44 tap target without making
   every slider look oversized on a laptop. */
.scale-row { display: flex; align-items: center; gap: 14px; }
.scale-row input[type=range] { flex: 1; min-width: 0; width: 100%; height: 44px; margin: 0; accent-color: var(--cab-blue-dark); cursor: pointer; background: transparent; }
.scale-readout { font: 700 1rem/1 var(--font-mono); min-width: 2.4ch; text-align: right; color: var(--ink); flex: none; }
.trow-readonly { margin: 4px 0 8px; padding: 8px 0 2px; color: var(--ink); font-size: 1rem; line-height: 1.5; }
/* CERT-088 phone audit finding 4: a checkbox is a replaced form control, and
   browsers do not render generated ::before/::after content on replaced
   elements, so a pseudo-element cannot enlarge its hit area. The reliable,
   handler-safe technique is the native one: clicking anywhere inside a
   <label> associated with a checkbox (by wrapping it or by for/id) fires a
   real click on the checkbox itself, so the existing onchange attribute on
   the input keeps working unchanged. .cb-tap is used where a checkbox has no
   visible label text of its own (the Phases document picker); every other
   checkbox already sits inside a <label>, so the phone rule below enlarges
   that label instead of touching the input. */
.cb-tap { display: inline-flex; align-items: center; justify-content: center; cursor: pointer; }
fieldset { border: 1px solid var(--hairline); border-radius: var(--radius); padding: 16px 18px; margin: 16px 0 0; background: var(--surface); }
legend { font-weight: 700; color: var(--cab-blue-dark); padding: 0 8px; font-size: .95rem; }
.sec-desc { font-size: .95rem; color: var(--ink); margin: 2px 0 14px; }
.radio-row { display: flex; align-items: center; gap: 10px; padding: 6px 0; }
.radio-row input[type="checkbox"], .radio-row input[type="radio"] { margin: 0; flex: none; }
.radio-row label { margin: 0; font-weight: 400; font-size: .95rem; cursor: pointer; }
.row { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.grow { flex: 1; min-width: 200px; }
/* The phase list on a production's Overview. It used to be one bordered
   .doc-row per phase, the same shape as the work rows underneath, so the
   progress summary and the list of things actually owed read as equals.
   Quiet strip, current phase bold, so the only list with rules on that
   page is the work the student can act on. */
.phase-strip { margin: 0 0 18px; color: var(--muted); font-size: .86rem; line-height: 1.6; }
.phase-strip strong { color: var(--ink); }
.role-picker{min-width:230px;border:1px solid var(--line);border-radius:var(--radius-card);background:var(--cab-white)}
.role-picker>summary{padding:10px 12px;cursor:pointer;color:var(--navy);font-weight:650}
.role-picker__options{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:4px 12px;padding:4px 12px 12px}
.role-picker__options .radio-row{margin:0;min-height:32px}
@media(max-width:520px){.role-picker{width:100%}.role-picker__options{grid-template-columns:1fr}}
/* Opportunities use one flat visual level. The notice, application fields,
   and instructor controls are separated by hairlines instead of cards or
   accordions nested inside other cards. */
.opp-list{border:1px solid var(--hairline);border-radius:var(--radius);background:var(--surface);overflow:hidden}
.opp-card{padding:20px 22px;border-bottom:1px solid var(--hairline)}
.opp-card:last-child{border-bottom:0}
.opp-card__head{display:flex;align-items:flex-start;gap:12px;flex-wrap:wrap}
.opp-card__meta{display:flex;gap:7px;flex-wrap:wrap;margin-top:7px}
.opp-card__body{max-width:720px;margin-top:12px}
.opp-application{margin-top:18px;padding-top:18px;border-top:1px solid var(--hairline);max-width:720px}
.opp-roles{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px 18px;margin:8px 0 4px}
.opp-roles .radio-row{padding:2px 0}
.opp-editor{max-width:820px;border:1px solid var(--hairline);border-radius:var(--radius);background:var(--surface);padding:22px}
.opp-editor__section{padding:0 0 20px;margin:0 0 20px;border:0;border-bottom:1px solid var(--hairline);border-radius:0;background:transparent}
.opp-editor__section:last-of-type{margin-bottom:0}
.opp-editor__section legend{padding:0;margin:0 0 8px;font-size:.95rem}
.opp-responses{margin:0 0 22px;padding:0 22px 20px;border:1px solid var(--hairline);border-top:0;border-radius:var(--radius-none);background:var(--surface)}
@media(max-width:640px){.opp-roles{grid-template-columns:1fr}.opp-editor{padding:16px}.opp-card{padding:17px 16px}}
.mt-6 { margin-top: 28px; }
.grp { margin-top: 34px; }
.ok-note { background: var(--ok-bg); border-left: 4px solid var(--ok); border-radius:var(--radius-md); padding: 14px 18px; }
.icon { width: 18px; height: 18px; flex: 0 0 18px; vertical-align: -3px; }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.back-link { font: 600 .78rem/1.4 var(--font-mono); letter-spacing: .07em; text-decoration: none; color: var(--text-link); }
.back-link:hover { text-decoration: underline; }
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition-duration: .01ms !important; animation-duration: .01ms !important; }
}
@media (max-width: 720px) {
  .btn, .btn-small, #inst-main .btn-small { min-height: var(--control-height-phone); }
  input[type=text], input[type=email], input[type=password], input[type=tel], input[type=date], input[type=time], input[type=number], input[type=url], select { min-height: var(--control-height-phone); }
  /* CERT-088 phone audit finding 7: a plain `.quiet` button (Attendance's
     "Show term totals" and "Remove this register") carries no .btn class, so
     the min-height rule above never reached it; .section-head .quiet renders
     at padding:0 with a 20px line-height, well under the 44px phone target.
     Centered flex layout keeps the label from sitting at the top of the new
     taller box. */
  .quiet { min-height: var(--control-height-phone); display: inline-flex; align-items: center; }
}
@media (max-width: 640px) {
  h1 { font-size: 1.4rem; }
  .card { padding: 16px; }
  .kpi-row { grid-template-columns: repeat(2, 1fr); }
}
/* ---------- portal-specific ---------- */
.view{display:none}.view.active{display:block}
#preview-banner:not([hidden]){display:flex;align-items:center;gap:12px;flex-wrap:wrap}
.auth-shell{max-width:430px;margin:6vh auto 0}
/* The sign-in Student/Instructor toggle. Named apart from .seg on purpose:
   it used to share that class with the Phases required/available/hidden
   control, and being declared later it silently overrode the Phases
   selected state and sizing. */
.authseg{display:flex;background:var(--idle-bg);border-radius:var(--radius-pill);padding:4px;margin:18px 0}
.authseg button{flex:1;font:600 .88rem/1 var(--font-body);border:0;border-radius:var(--radius-pill);padding:12px;min-height:44px;cursor:pointer;background:transparent;color:var(--muted);transition:background-color var(--dur-fast) var(--ease-standard),color var(--dur-fast) var(--ease-standard)}
.authseg button[aria-selected=true]{background:var(--surface);color:var(--cab-blue-dark);box-shadow:var(--shadow)}
.prod-card{display:block;width:100%;text-align:left;font:inherit;background:var(--surface);border:1px solid var(--hairline);border-radius:var(--radius);box-shadow:var(--shadow);padding:18px 20px;margin-bottom:12px;cursor:pointer;transition:border-color var(--dur-fast) var(--ease-standard)}
.prod-card:hover{border-color:var(--cab-blue-dark)}
.fcard{background:var(--surface);border:1px solid var(--hairline);border-radius:var(--radius);box-shadow:var(--shadow);margin-bottom:10px}
.fcard>button.fhead{display:flex;align-items:center;gap:14px;width:100%;text-align:left;background:none;border:0;padding:15px 18px;min-height:44px;cursor:pointer;font:inherit;border-radius:var(--radius);transition:background-color var(--dur-fast) var(--ease-standard)}
.fcard>button.fhead:hover{background:var(--surface-tint)}
.fbody{padding:0 18px 18px;border-top:1px solid var(--hairline)}
.clear-band{display:flex;align-items:center;gap:12px;border-radius:var(--radius);padding:14px 18px;margin:16px 0;font-weight:600}
.clear-band.studio-band{display:block;overflow-wrap:anywhere}
.clear-band.studio-band > p{margin:var(--space-2) 0 0}
.clear-yes{background:var(--ok-bg);color:var(--ok)}
.clear-no{background:var(--surface-tint);color:var(--cab-blue-dark)}
/* The date control is three fixed-width pieces; the picker label that holds
   it must grow with them, or the arrows spill under the action pills. */
.phase-pick:has(> .att-daterow){max-width:none;min-width:0}
.att-daterow{display:flex;gap:6px;align-items:center;flex-wrap:nowrap}
.att-daterow .btn{padding-left:10px;padding-right:10px;min-width:36px}
.att-daterow input[type=date]{min-width:150px}
/* Same rule: width only, so the roll's date matches every other control. */
.att-daterow input[type=date]{width:auto;color:var(--cab-blue-dark);font-weight:600}
.att-daterow .btn{flex:none}
.att-tbl td{padding-top:8px;padding-bottom:8px}
.att-tbl .att-set{width:340px;text-align:right}
.attseg{display:inline-flex;gap:0;border:1px solid var(--hairline);border-radius:var(--radius-pill);overflow:hidden}
.attbtn{font:600 .78rem/1 var(--font-body);padding:9px 13px;min-height:40px;background:var(--surface);
  color:var(--muted);border:0;border-right:1px solid var(--hairline);cursor:pointer;
  transition:background-color var(--dur-fast) var(--ease-standard),color var(--dur-fast) var(--ease-standard)}
.attbtn:last-child{border-right:0}
.attbtn:hover{background:var(--surface-tint);color:var(--cab-blue-dark)}
.attbtn--on{color:var(--cab-white)}
/* Phones: the register stacks. The name reads on its own line, the whole
   button set stretches edge to edge underneath with real thumb targets,
   and nothing hides behind a sideways scroll: taking the roll happens
   standing in front of a class holding a phone. */
@media (max-width: 700px) {
  .att-tbl, .att-tbl tbody, .att-tbl tr, .att-tbl td { display: block; width: 100%; box-sizing: border-box; }
  .att-tbl tr { border-bottom: 1px solid var(--hairline); padding: 10px 4px; }
  .att-tbl td { border: 0; padding: 4px 8px; }
  .att-tbl .att-set { width: 100%; text-align: left; padding: 6px 8px 4px; }
  .attseg { display: flex; width: 100%; }
  .attbtn { flex: 1 1 0; min-height: 44px; padding: 9px 4px; }

  /* The roll starts high on a phone: stats become one wrapping line of
     compact chips instead of three screens of cards. */
  .att-kpis { display: flex; flex-wrap: wrap; gap: 6px; }
  .att-kpis .kpi { display: flex; gap: 8px; align-items: baseline; padding: 6px 12px; }
  .att-kpis .k-value { font-size: 1.1rem; }
  .att-kpis .k-sub { display: none; }

  /* Roster rows become cards: name opens the record, course and status
     ride along, the rest lives on the student record page. */
  .roster-tbl thead { display: none; }
  .roster-tbl, .roster-tbl tbody { display: block; width: 100%; }
  .roster-tbl tr { display: block; padding: 10px 4px; border-bottom: 1px solid var(--hairline); }
  .roster-tbl td { display: inline-block; border: 0; padding: 2px 10px 2px 0; }
  .roster-tbl td:first-child { display: block; padding-bottom: 4px; }
  .roster-tbl td:nth-child(3), .roster-tbl td:nth-child(4), .roster-tbl td:nth-child(5) { display: none; }
  .roster-tbl td:last-child { display: none; position: static; border-left: 0; }

  /* Equipment rows become cards: full-width name, counts as labeled
     chips beneath, actions on their own line. No word towers. */
  .eq-tbl thead { display: none; }
  .eq-tbl, .eq-tbl tbody { display: block; width: 100%; }
  .eq-tbl tr { display: block; padding: 10px 4px; border-bottom: 1px solid var(--hairline); }
  .eq-tbl td { display: inline-block; border: 0; padding: 2px 12px 2px 0; }
  .eq-tbl td:first-child { display: block; padding-bottom: 4px; }
  .eq-tbl td:nth-child(2)::before { content: "Course "; }
  .eq-tbl td:nth-child(3)::before { content: "Total "; }
  .eq-tbl td:nth-child(4)::before { content: "Out "; }
  .eq-tbl td:nth-child(5)::before { content: "Available "; }
  .eq-tbl td::before { font: 600 .66rem/1.4 var(--font-mono); letter-spacing: .08em;
    text-transform: uppercase; color: var(--muted); }
  .eq-tbl td:last-child { display: block; padding-top: 6px; }
}
/* Sub-navigation inside a pane. Several screens had grown into one long
   scroll — forms, then course forms, then documents, then the roster — and
   finding the third of four meant scrolling past the other three. */
.th-sort{appearance:none;background:none;border:0;padding:0;font:inherit;font-weight:inherit;
  letter-spacing:inherit;text-transform:inherit;color:inherit;cursor:pointer;white-space:nowrap}
.th-sort:hover{color:var(--cab-blue-dark)}
.th-sort:focus-visible{outline:2px solid var(--cab-blue-dark);outline-offset:2px}
th[aria-sort="ascending"] .th-sort,th[aria-sort="descending"] .th-sort{color:var(--cab-blue-dark)}
.subtabs{display:flex;gap:2px;flex-wrap:wrap;border-bottom:2px solid var(--hairline);margin:16px 0 18px}
.forms-toolbar{display:flex;flex-wrap:wrap;gap:16px;margin-bottom:18px}
.forms-toolbar>div{flex:0 1 220px;min-width:0;max-width:100%}
  .forms-toolbar label{margin-top:0}
  #ipane-forms .subtab{min-height:44px}
.subtab{appearance:none;background:none;border:0;border-bottom:2px solid transparent;margin-bottom:-2px;
  padding:9px 14px;font:inherit;font-weight:600;color:var(--muted);cursor:pointer;
  border-radius:var(--radius-none);min-height:40px}
.subtab:hover{background:var(--surface-tint);color:var(--cab-blue-dark)}
.subtab[aria-selected="true"]{color:var(--cab-blue-dark);border-bottom-color:var(--cab-blue)}
.subtab:focus-visible{outline:2px solid var(--cab-blue-dark);outline-offset:2px}
.subtab .drow-tag{margin-left:6px}
@media (max-width:640px){ .subtab{padding:9px 10px;font-size:.92rem} }
.docs-head h2{margin:0 0 4px}
.docs-head p{margin:0;max-width:70ch}
.docs-tabs{margin:18px 0 12px;flex-wrap:nowrap;overflow-x:auto;overscroll-behavior-inline:contain;
  scrollbar-width:thin;scrollbar-color:var(--hairline) transparent}
.docs-tabs .subtab{flex:none;white-space:nowrap}
/* Beta's own audit, 20 Sep 2026: the student Updates tab bar
   (PostUI.studentTabs, posts.js), built on the same plain .subtabs base as
   .docs-tabs and .production-workspace .subtabs above, wrapped Announcements
   / Opportunities / Casting & Crew onto a second line at phone width
   instead of scrolling like its two already-fixed siblings. Same fix,
   scoped to this pane only so it does not touch any other .subtabs use. */
#student-pane-opportunities .subtabs{flex-wrap:nowrap;overflow-x:auto;overscroll-behavior-inline:contain;
  scrollbar-width:thin;scrollbar-color:var(--hairline) transparent}
#student-pane-opportunities .subtabs .subtab{flex:none;white-space:nowrap}
/* FH-20260913: the instructor Documents phase-pill row (.qf) hit the same
   silent-wrap problem .docs-tabs was already fixed for, once Contracts made
   it an eighth pill alongside the search box. Same fix, scrolls instead of
   stacking; the search box moves out of this row entirely (.docf-search
   below) so it is never competing with the pills for space. */
.qf-scroll{overflow-x:auto;overscroll-behavior-inline:contain;scrollbar-width:thin;scrollbar-color:var(--hairline) transparent;margin:0 0 16px}
.qf-scroll .qf{flex-wrap:nowrap;margin:0}
.qf-scroll .qf__b{flex:none;white-space:nowrap}
.docf-search{display:block;margin:0 0 16px;max-width:320px;width:100%}
/* scrollbar-color/-width above only style Firefox. Without a matching
   ::-webkit-scrollbar rule, Chrome/Safari fall back to the OS default,
   which on hover can render as a thick bar sitting on top of the pills
   instead of a thin line beneath them (reported live, 13 Sep 2026: General
   overlapped by a gray bar on hover). Same three rows, one thin, always
   reserved (not overlay) scrollbar track for all of them. */
.docs-tabs,.qf-scroll,.production-workspace .subtabs,#student-pane-opportunities .subtabs{scrollbar-gutter:stable}
.docs-tabs::-webkit-scrollbar,.qf-scroll::-webkit-scrollbar,.production-workspace .subtabs::-webkit-scrollbar,#student-pane-opportunities .subtabs::-webkit-scrollbar{height:5px}
.docs-tabs::-webkit-scrollbar-track,.qf-scroll::-webkit-scrollbar-track,.production-workspace .subtabs::-webkit-scrollbar-track,#student-pane-opportunities .subtabs::-webkit-scrollbar-track{background:transparent}
.docs-tabs::-webkit-scrollbar-thumb,.qf-scroll::-webkit-scrollbar-thumb,.production-workspace .subtabs::-webkit-scrollbar-thumb,#student-pane-opportunities .subtabs::-webkit-scrollbar-thumb{background:var(--hairline);border-radius:var(--radius-pill)}
.docs-tools{display:grid;grid-template-columns:minmax(220px,360px) auto;gap:10px;align-items:center;
  max-width:680px;margin:0 0 18px}
.docs-tools input{margin:0}
.docs-tools .btn{justify-self:start;white-space:nowrap}
.docs-panel{max-width:920px}
.docs-panel__summary{margin:0 0 8px;color:var(--muted);font-size:.84rem}
.docs-list .doc-row{margin:0;padding:13px 2px;border:0;border-bottom:1px solid var(--hairline);
  border-radius:0;background:transparent;flex-wrap:nowrap}
.docs-list .doc-row:first-child{border-top:1px solid var(--hairline)}
.docs-list .doc-row .btn{margin-left:auto;flex:none}
.docs-empty{padding:18px 0;border-top:1px solid var(--hairline);border-bottom:1px solid var(--hairline)}
.docs-empty p{margin:0 0 8px}
@media(max-width:640px){
  .docs-tools{grid-template-columns:1fr}
  .docs-list .doc-row{align-items:flex-start;flex-wrap:wrap}
  .docs-list .doc-row .btn{margin-left:30px}
}
#ipane-prods{max-width:1120px}
/* Documents rows get the same width cap the Projects list uses, so a wide
   viewport never opens up the dead middle ground a full-bleed row leaves
   between a short title and a far-right action. */
#ipane-docs{max-width:1120px}
.production-page-head{margin-bottom:4px}
.production-page-head h2{margin:0 0 4px}
.production-page-head p{max-width:68ch;margin:0}
.production-workspace .subtabs{margin-top:18px;flex-wrap:nowrap;overflow-x:auto;overscroll-behavior-inline:contain;
  scrollbar-width:thin;scrollbar-color:var(--hairline) transparent}
.production-workspace .subtabs .subtab{flex:none;white-space:nowrap}
.production-workspace .card{box-shadow:none}
.production-section-head{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;margin-bottom:12px}
.production-section-head h2{margin:0 0 3px}
.production-section-head p{margin:0;max-width:64ch}
.production-empty{margin:0;padding:15px 0;border-top:1px solid var(--hairline);border-bottom:1px solid var(--hairline)}
.production-table{padding:0;overflow:hidden}
.production-tools{max-width:640px;margin-top:14px}
.cert-draft-list{margin-top:12px}
.cert-draft-list>.doc-row:last-child{margin-bottom:0}
.fhint{display:block;margin:-2px 0 6px;font-size:.85rem;color:var(--muted);font-weight:400}
.attnote{max-width:340px;font-size:.85rem;padding:5px 8px;min-height:30px}
.attnote-view{font-style:italic}
.attnote-link { border: 0; background: none; cursor: pointer; padding: 2px 6px;
  font: 600 .78rem/1 var(--font-body); color: var(--text-link); }
.attnote-link:hover { text-decoration: underline; }
.att-wait{border-color:var(--warn);color:var(--warn)}
/* Waitlisted rows sit back: readable, but visibly not the enrolled list. */
.att-row--wait td:first-child strong{color:var(--muted);font-weight:600}
.att-row--wait td:first-child{color:var(--muted)}
.att-present{background:var(--ok)}
.att-late{background:var(--warn)}
.att-excused{background:var(--cab-sky);color:var(--cab-blue-deep)}
.att-absent{background:var(--warn)}
.accessbar{display:flex;align-items:center;gap:12px;flex-wrap:wrap;border:1px solid var(--hairline);
  border-radius:var(--radius);padding:12px 16px;margin:0 0 16px;background:var(--surface)}
.accessbar__dot{width:9px;height:9px;border-radius:50%;flex:none}
.accessbar--shut{border-color:var(--warn)}
.accessbar--shut .accessbar__dot{background:var(--warn)}
.accessbar--open .accessbar__dot{background:var(--ok)}
.qrow{cursor:pointer}
.qrow[aria-current="true"]{background:var(--surface-tint);box-shadow:inset 3px 0 0 var(--cab-blue)}
.rv-bar{display:flex;align-items:center;gap:10px;flex-wrap:wrap;border-bottom:1px solid var(--hairline);margin:-4px 0 14px;padding-bottom:12px}
.rv-bar .rv-count{font:600 .72rem/1.5 var(--font-mono);letter-spacing:.08em;text-transform:uppercase;color:var(--muted)}
kbd{font:600 .78rem/1 var(--font-mono);background:var(--surface-tint);border:1px solid var(--hairline);border-radius:var(--radius-sm);padding:2px 5px}
.detail-panel{background:var(--surface);border:1px solid var(--hairline);border-radius:var(--radius);box-shadow:var(--shadow);padding:20px 22px;margin-top:14px}
.fv{margin:8px 0}
.fv .l{font:600 .66rem/1.5 var(--font-mono);letter-spacing:.09em;text-transform:uppercase;color:var(--text-label)}
.fv table{border-collapse:collapse;width:100%;font-size:.85rem}
.fv td,.fv th{border:1px solid var(--hairline);padding:6px 9px;text-align:left}
/* Crew Evaluation's peers table carries a comment meant to be shared context
   and a private note meant only for the instructor; both are plain prose
   columns that otherwise read alike (September 20). The private column gets
   a tint and italic so a skimming instructor does not conflate the two. */
.fv td.fv-private-note{background:var(--surface-tint);font-style:italic}
.doc-row{display:flex;align-items:center;gap:12px;flex-wrap:wrap;background:var(--surface);border:1px solid var(--hairline);border-radius:var(--radius);padding:12px 16px;margin-bottom:8px}
.doc-row--req{border-left:3px solid var(--cab-blue-dark)}
/* CERT-088 phone audit finding 9: remove the ~300ms tap delay on rows that
   are themselves the tap target. Not phone-scoped: touch-action has no
   effect on pointer/mouse input, so this is safe at every width, and it
   applies to both portals since app.css and portal-shared.php's tapAttrs()
   (role="button") are shared. */
.doc-row,.prep-item-row,[role="button"],table.data tbody tr{touch-action:manipulation}
/* Student checkout is organized by the way students ask for gear, while
   every physical unit remains selectable for accurate cage records. */
.student-equip-request{max-width:760px;margin:12px 0 0;box-shadow:none}
.student-equip-request__head{padding-bottom:16px;border-bottom:1px solid var(--hairline)}
.student-equip-request__head h3{margin:0 0 4px;font-size:1.02rem}
.student-equip-request__head p{margin:0;max-width:62ch}
.student-equip-groups{margin-top:4px}
.student-equip-category{border-bottom:1px solid var(--hairline)}
.student-equip-category>summary,.student-equip-model>summary{display:flex;align-items:center;gap:12px;list-style:none;cursor:pointer}
.student-equip-category>summary::-webkit-details-marker,.student-equip-model>summary::-webkit-details-marker{display:none}
.student-equip-category>summary{min-height:54px;padding:13px 2px;color:var(--cab-blue-dark)}
.student-equip-category>summary::after,.student-equip-model>summary::after{content:"+";flex:none;margin-left:4px;color:var(--muted);font:500 1.05rem/1 var(--font-body)}
.student-equip-category[open]>summary::after,.student-equip-model[open]>summary::after{content:"\2212"}
.student-equip-category__name,.student-equip-model__name{min-width:0;flex:1}
.student-equip-summary{flex:none;color:var(--muted);font-size:.78rem;white-space:nowrap}
.student-equip-category__body{padding:0 0 12px}
.student-equip-model{border-top:1px solid var(--hairline)}
.student-equip-model:first-child{border-top:0}
.student-equip-model>summary{min-height:48px;padding:11px 12px;background:var(--surface-tint);color:var(--ink)}
.student-equip-model__body{padding:0 12px 4px;background:var(--surface-tint)}
.student-equip-unit{display:grid;grid-template-columns:minmax(0,1fr) 88px;gap:14px;align-items:center;padding:11px 0;border-top:1px solid var(--hairline)}
.student-equip-unit:first-child{border-top:0}
.student-equip-unit__name{display:flex;align-items:center;gap:6px;flex-wrap:wrap;min-width:0}
.student-equip-unit__meta{display:block;margin-top:2px}
.student-equip-unit__control{display:flex;align-items:center;justify-content:flex-end;gap:8px;margin:0;color:var(--text-link);font-size:.78rem;cursor:pointer}
.student-equip-unit__control input[type=checkbox]{flex:none;margin:0}
.student-equip-unit__control input[type=number]{width:72px;min-height:38px;padding:7px 9px;text-align:center}
.student-equip-includes{margin-top:4px}
.student-equip-includes>summary{width:max-content;max-width:100%;color:var(--text-link);font-size:.78rem;font-weight:600;cursor:pointer}
.student-equip-includes p{margin:5px 0 0;max-width:62ch}
.student-equip-checkout{margin-top:18px;padding-top:18px;border-top:1px solid var(--hairline)}
.student-equip-checkout h3{margin:0 0 2px}
.student-equip-care{margin:12px 0 0;padding:10px 0;border-top:1px solid var(--hairline);border-bottom:1px solid var(--hairline)}
@media(max-width:560px){
  .student-equip-request{padding:16px}
  .student-equip-summary{white-space:normal;text-align:right}
  .student-equip-unit{grid-template-columns:minmax(0,1fr) 76px;gap:10px}
  .student-equip-unit__control{font-size:.74rem}
}
.prep-item-row{padding:9px 0;margin:0;border:0;border-bottom:1px solid var(--hairline);border-radius:0}
.prep-item-row:first-child{border-top:1px solid var(--hairline)}
.prep-item-view{display:flex;align-items:center;gap:10px;width:100%}
.prep-item-check{display:flex;align-items:center;gap:9px;min-width:0;flex:1;margin:0;font-weight:400;cursor:pointer}
.prep-item-label{overflow-wrap:anywhere}
.prep-item-actions{display:flex;align-items:center;gap:2px;margin-left:auto}
.prep-item-action{appearance:none;border:0;background:transparent;padding:5px 7px;color:var(--text-link);font:600 .76rem/1.2 var(--font-body);cursor:pointer;border-radius:var(--radius-sm)}
.prep-item-action:hover{background:var(--surface-tint)}
.prep-item-action--remove{color:var(--warn)}
.prep-item-edit{display:grid;grid-template-columns:minmax(180px,1fr) auto auto;align-items:center;gap:6px;width:100%}
.prep-item-edit input{margin:0;min-height:36px;padding:7px 9px;font-size:.86rem}
.prep-item-view[hidden],.prep-item-edit[hidden]{display:none}
.prep-oneoff{margin-top:18px;padding-top:15px;border-top:1px solid var(--hairline)}
.prep-oneoff h4{margin:0 0 3px;font-size:.9rem}
.prep-oneoff>p{margin:0 0 10px}
@media(max-width:560px){.prep-item-edit{grid-template-columns:1fr auto}.prep-item-edit input{grid-column:1/-1}.prep-item-view{align-items:flex-start}.prep-item-actions{flex:0 0 auto}}
.rq{font:600 .62rem/1.5 var(--font-mono);letter-spacing:.08em;text-transform:uppercase;border-radius:99px;padding:2px 9px;white-space:nowrap;vertical-align:middle}
.rq-req{background:var(--cab-blue-dark);color:var(--cab-white)}
.rq-cond{background:var(--warn-bg);color:var(--warn)}
.rq-count{background:var(--surface-tint);color:var(--cab-blue-dark);margin-left:6px}
.rq-how{color:var(--muted)}
.tabbar{display:flex;gap:6px;border-bottom:2px solid var(--hairline);margin:20px 0 18px;flex-wrap:wrap}
.tabbar button{font:600 .88rem/1 var(--font-body);background:none;border:0;border-bottom:3px solid transparent;color:var(--muted);padding:10px 14px;min-height:44px;cursor:pointer;transition:color var(--dur-fast) var(--ease-standard),border-color var(--dur-fast) var(--ease-standard)}
.tabbar button[aria-selected=true]{color:var(--cab-blue-dark);border-bottom-color:var(--cab-blue)}
.who-strip{display:flex;align-items:center;gap:6px;flex-wrap:wrap;font-size:.85rem;color:var(--muted);margin:6px 0 0}
.student-layout{display:grid;grid-template-columns:210px minmax(0,1fr);gap:26px;align-items:start;margin-top:24px}
.student-nav{position:sticky;top:16px;background:var(--surface);border:1px solid var(--hairline);border-radius:var(--radius);box-shadow:var(--shadow);padding:8px}
.student-nav__label{font:600 .6rem/1.4 var(--font-mono);letter-spacing:.12em;text-transform:uppercase;color:var(--muted);margin:6px 10px 5px;padding-bottom:6px;border-bottom:1px solid var(--hairline)}
.student-nav button{display:flex;align-items:center;width:100%;min-height:42px;padding:9px 11px;border:0;border-left:3px solid transparent;border-radius:var(--radius-card);background:transparent;color:var(--muted);font:600 .9rem/1.2 var(--font-body);text-align:left;cursor:pointer}
.student-nav button:hover{background:var(--surface-tint);color:var(--cab-blue-dark)}
.student-nav button[aria-current=true]{background:var(--surface-tint);color:var(--cab-blue-dark);border-left-color:var(--cab-blue)}
.student-nav__account{margin-top:8px;padding-top:8px;border-top:1px solid var(--hairline)}
.student-pane[hidden]{display:none}
.student-pane__head{margin-bottom:16px}
.student-pane__head p{max-width:680px;margin:4px 0 0}
.role-work{margin:0 0 22px;border:0;border-radius:var(--radius-card);background:var(--surface);padding:20px 24px}
.role-work__top{display:flex;align-items:flex-start;justify-content:space-between;gap:18px}
.role-work__title{margin:2px 0 4px;font-size:1.15rem}
.role-work__meta{margin:0;color:var(--muted);font-size:.86rem;line-height:1.55}
.role-work__list{margin:16px 0 18px;padding-left:20px;max-width:760px}
.role-work__list li{margin:7px 0;line-height:1.5}
/* Hard rule on actions, 19 Sep 2026: this row never wraps or stacks. Only
   two quiet nav actions live here, both short enough to hold one line at
   320px (see portal-student.php's StudentRoles.dashboard). */
.role-work__actions{display:flex;flex-wrap:nowrap;gap:8px;min-width:0}
.role-work__actions>.btn{flex:none;white-space:nowrap}
.role-guide{max-width:920px}
.role-guide__header{padding-bottom:20px;border-bottom:1px solid var(--hairline)}
.role-guide__header h2{margin:8px 0 6px}
.role-guide__switcher{display:flex;gap:7px;flex-wrap:wrap;margin:18px 0 26px}
.role-guide__switcher button{min-height:36px;padding:7px 11px;border:1px solid var(--hairline);border-radius:var(--radius-md);background:var(--surface);color:var(--muted);font:600 .78rem/1.2 var(--font-body);cursor:pointer}
.role-guide__switcher button:hover,.role-guide__switcher button[aria-current=true]{border-color:var(--cab-blue-dark);color:var(--cab-blue-dark);background:var(--surface-tint)}
.role-guide__grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px}
.role-guide__section{border:1px solid var(--hairline);border-radius:var(--radius-card);background:var(--surface);padding:20px}
.role-guide__section h3{margin:0 0 10px;font-size:1rem}
.role-guide__section p,.role-guide__section li{font-size:.9rem;line-height:1.6}
.role-guide__section ul{margin:0;padding-left:19px}
.role-guide__section li+li{margin-top:6px}
.role-guide__wide{grid-column:1/-1}
.quick-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:12px;margin-top:14px}
.quick-card{background:var(--surface);border:1px solid var(--hairline);border-radius:var(--radius);box-shadow:var(--shadow);padding:16px 18px}
.quick-card p{margin:4px 0 12px}
.overview-actions{display:flex;flex-wrap:wrap;gap:8px;margin:0 0 20px;padding-bottom:16px;border-bottom:1px solid var(--hairline)}
.section-line{display:flex;align-items:center;justify-content:space-between;gap:12px;margin:0 0 8px}
.section-line h3{margin:0}
.recent-list{border-top:1px solid var(--hairline);margin-top:24px;padding-top:18px}
.recent-list .doc-row{padding-left:0;padding-right:0}
.cal-wrap{display:grid;grid-template-columns:repeat(auto-fit,minmax(238px,1fr));gap:14px;margin-top:10px}
.cal-month{background:var(--surface);border:1px solid var(--hairline);border-radius:var(--radius-card);padding:12px}
.cal-title{font:600 .8rem/1.4 var(--font-mono);color:var(--cab-blue-dark);text-align:center;margin-bottom:8px}
.cal-days{display:grid;grid-template-columns:repeat(7,1fr);gap:3px}
.cal-dow{font:600 .6rem/1.4 var(--font-mono);color:var(--muted);text-align:center;padding:2px 0}
.cal-day{font:500 .8rem/1 var(--font-body);border:1px solid var(--hairline);background:var(--surface);border-radius:var(--radius-md);min-height:36px;cursor:pointer;color:var(--ink);transition:border-color var(--dur-fast) var(--ease-standard),background-color var(--dur-fast) var(--ease-standard)}
.cal-day:hover{border-color:var(--cab-blue-dark)}
.cal-day.cal-av{background:var(--ok-bg);border-color:var(--ok);color:var(--ok);font-weight:700}
.cal-day.cal-un{background:var(--warn-bg);border-color:var(--warn);color:var(--warn);font-weight:700;text-decoration:line-through}
.cal-day.cal-disabled{background:var(--bg);color:var(--muted);opacity:.48;cursor:not-allowed;text-decoration:none}
button.cal-day:not(.cal-blank){min-height:44px}
.cal-blank{visibility:hidden}
.cal-chip{display:inline-block;width:12px;height:12px;border-radius:var(--radius-sm);vertical-align:-1px}
.cal-chip.cal-av{background:var(--ok-bg);border:1.5px solid var(--ok)}
.cal-chip.cal-un{background:var(--warn-bg);border:1.5px solid var(--warn)}
/* ---------- instructor sidebar (DESIGN-SYSTEM.md section 5, draft 6) ----------
   One level in three groups, an icon on every item, the active page a white
   fill with a 2 px Bright Blue bar. Nothing folds. */
.inst-layout{display:grid;grid-template-columns:240px minmax(0,1fr);gap:26px;align-items:start;margin-top:8px}
.inst-refresh-notice{display:flex;align-items:center;justify-content:space-between;flex-wrap:nowrap;gap:16px;
  margin:0 0 18px;padding:12px 16px;border-left:4px solid var(--warn);background:var(--warn-bg);
  color:var(--ink);font-size:1rem;line-height:1.5}
.inst-refresh-notice[hidden]{display:none}
.inst-refresh-notice span{min-width:0;max-width:68ch}
.inst-refresh-notice .btn{flex:none;white-space:nowrap}
.side-nav{position:sticky;top:16px;background:transparent;border:0;border-radius:0;box-shadow:none;padding:4px 0 0;display:flex;flex-direction:column;gap:0}
.nav-group{display:flex;flex-direction:column;margin-bottom:14px}
.nav-group__name{display:block;font:600 10px/16px var(--font-body);letter-spacing:.1em;color:var(--cab-ink-45);text-transform:uppercase;padding:0 12px 6px}
.side-nav button[data-pane]{display:flex;align-items:center;gap:12px;width:100%;text-align:left;font:500 .9rem/1.4 var(--font-body);background:none;border:0;border-left:2px solid transparent;border-radius:0;color:var(--ink);padding:8px 12px;min-height:38px;cursor:pointer;transition:background-color var(--dur-fast) var(--ease-standard),color var(--dur-fast) var(--ease-standard)}
.side-nav button[data-pane] svg{width:18px;height:18px;stroke:currentColor;fill:none;stroke-width:1.75;stroke-linecap:round;stroke-linejoin:round;flex:none;opacity:.8}
.side-nav button[data-pane]:hover{background:var(--surface);color:var(--ink)}
.side-nav button[data-pane][aria-current=true]{font-weight:700;background:var(--cab-blue);color:var(--cab-white);border-left:3px solid var(--cab-blue-dark)}
.side-nav button[data-pane][aria-current=true] svg{opacity:1;stroke:var(--cab-white)}
.side-nav .badge{margin-left:auto;font:600 .68rem/1 var(--font-mono);background:var(--warn-bg);color:var(--warn);border-radius:var(--radius-pill);padding:4px 8px}
.bbar{display:none}
/* ---------- instructor workspace ----------
   One visual grammar for every instructor destination. Cabrillo blue owns
   navigation and headings, orange is reserved for the primary action, and
   structure comes from spacing and hairlines instead of nested panels. */
#inst-main{min-width:0;max-width:1120px}
.ipane{min-width:0}
.inst-page-head{display:flex;align-items:flex-start;justify-content:space-between;gap:22px;
  padding:0 0 15px;margin:0 0 18px;border-bottom:1px solid var(--hairline)}
.inst-page-head__copy{min-width:0;max-width:72ch}
.inst-page-head h2{margin:0;color:var(--cab-blue-dark);font-size:1.3rem;line-height:1.2;letter-spacing:-.015em}
.inst-page-head p{margin:5px 0 0;color:var(--muted);font-size:.88rem;line-height:1.55}
.inst-page-head__actions{display:flex;align-items:center;justify-content:flex-end;gap:8px;flex-wrap:wrap;flex:none}
.inst-page-head__actions .btn{white-space:nowrap}
.inst-toolbar{display:flex;align-items:flex-end;gap:10px;flex-wrap:wrap;margin:0 0 14px}
.inst-toolbar__title{margin:0;color:var(--ink);font-size:1rem;font-weight:600}
.inst-toolbar__actions{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-left:auto}
.inst-section{margin-top:24px}
.inst-section:first-child{margin-top:0}
.inst-section-head{display:flex;align-items:baseline;justify-content:space-between;gap:12px;margin:0 0 8px}
.inst-section-head h3{margin:0;font-size:.98rem}
.inst-empty{margin:0;padding:14px 0;color:var(--muted);font-size:.86rem;line-height:1.55;
  border-top:1px solid var(--hairline);border-bottom:1px solid var(--hairline)}
#inst-main .card{box-shadow:none;padding:16px 18px}
#inst-main .card--tint{background:transparent;border-color:var(--hairline)}
#inst-main .kpi{box-shadow:none;border-radius:var(--radius-card);padding:12px 14px}
#inst-main .kpi .k-value{font-size:1.45rem}
#inst-main .fold{border-radius:var(--radius-card);box-shadow:none}
#inst-main .fold>summary{padding:11px 14px;color:var(--ink);font-size:.9rem;font-weight:600}
#inst-main .fold>summary::after{content:"+";width:auto;height:auto;border:0;transform:none;
  color:var(--muted);font:500 1.05rem/1 var(--font-body);transition:none}
#inst-main .fold[open]>summary::after{content:"\2212";transform:none}
#inst-main .fold__body{padding:13px 14px 15px}
#inst-main .btn-small{min-height:var(--control-height)}
#inst-main .doc-row{padding-top:11px;padding-bottom:11px}
#inst-main .eq-group{border-radius:var(--radius-card);box-shadow:none}
#inst-main .eq-group>summary::after{content:"+";font-size:1rem;font-weight:500;color:var(--muted)}
#inst-main .eq-group[open]>summary::after{content:"\2212"}
.chips{display:flex;gap:8px;flex-wrap:wrap;margin:0 0 14px}
.chips button{font:600 .78rem/1 var(--font-mono);border:1.5px solid var(--hairline);background:var(--surface);color:var(--muted);border-radius:99px;padding:8px 13px;min-height:36px;cursor:pointer}
.chips button[aria-pressed=true]{border-color:var(--cab-blue-dark);color:var(--cab-blue-dark);background:var(--surface-tint)}
.drow-tag{font:600 .64rem/1.4 var(--font-mono);border:1px solid var(--hairline);border-radius:99px;padding:2px 9px;color:var(--muted);white-space:nowrap}
.drow-off{opacity:.55}
.fb-sec{border:1px solid var(--hairline);border-left:4px solid var(--cab-blue-dark);border-radius:var(--radius-card);padding:6px 16px 16px;margin:14px 0;background:var(--surface)}
.fb-field{border:1px solid var(--hairline);border-radius:var(--radius-card);padding:4px 14px 14px;margin:10px 0;background:var(--bg)}
.fb-tools{display:flex;gap:6px;align-items:center;margin-left:auto}
.fb-tools button{font:600 .8rem/1 var(--font-mono);border:1px solid var(--hairline);background:var(--surface);color:var(--muted);border-radius:var(--radius-md);padding:6px 9px;min-height:32px;cursor:pointer}
.fb-tools button:hover{color:var(--cab-blue-dark);border-color:var(--cab-blue-dark)}
@media (max-width: 720px) {
  /* CERT-079: builder tools remain separate tap targets beside long field keys. */
  .fb-sec > .row, .fb-field > .row { flex-wrap: wrap; }
  .fb-sec > .row > .cab-label, .fb-field > .row > .cab-caption { min-width: 0; max-width: 100%; white-space: normal; overflow-wrap: anywhere; }
  .fb-tools { flex-wrap: wrap; max-width: 100%; }
  .fb-tools button { min-height: var(--control-height-phone); min-width: var(--control-height-phone); flex-shrink: 0; }
}
@media (max-width: 720px) {
  /* Official preparation: long names keep their width above the state pill. */
  .studio-requirements .tc .r2 { display: grid; grid-template-columns: minmax(0, 1fr) auto; }
  .studio-requirements .tc .r2 .item { grid-column: 1 / -1; }
  .studio-requirements .tc .r2 .st { justify-self: start; max-width: 100%; white-space: normal; overflow-wrap: anywhere; }
  .studio-permission { display: block; }
}
#documentary-placement{max-width:1040px}
.placement-heading{display:flex;align-items:flex-start;justify-content:space-between;gap:18px;margin-bottom:12px}
.placement-heading h2{margin:0 0 3px}
.placement-heading p{margin:0;max-width:58ch}
.placement-meta{display:flex;align-items:center;justify-content:flex-end;gap:7px;flex-wrap:wrap}
.placement-overview{max-width:none;margin:0 0 14px;padding:0;border:0;border-radius:0;background:transparent;box-shadow:none}
.placement-settings{border-top:1px solid var(--hairline);margin-top:10px;padding-top:9px}
.placement-settings>summary,.placement-rules>summary{width:max-content;color:var(--text-link);font-size:.8rem;font-weight:600;cursor:pointer}
.placement-settings__body{display:grid;grid-template-columns:minmax(0,1.4fr) minmax(220px,.6fr);gap:12px 18px;align-items:end;padding-top:10px}
.placement-settings__field label{margin:0 0 4px;color:var(--muted);font-size:.72rem}
.placement-settings__field select,.placement-settings__field input{min-height:38px;padding:7px 10px;font-size:.86rem}
.placement-settings__control{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:8px;align-items:end}
.placement-settings__actions{grid-column:1/-1;display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.placement-swap{display:grid;grid-template-columns:minmax(170px,.9fr) minmax(0,1fr) minmax(0,1fr) auto;gap:9px;align-items:end;margin:0;padding:12px 0;border-top:1px solid var(--hairline);border-bottom:1px solid var(--hairline)}
.placement-swap__intro{margin:0;align-self:center}
.placement-swap__intro .cab-small{display:block;margin-top:2px}
.placement-swap label{display:block;margin:0;color:var(--muted);font-size:.72rem}
.placement-swap select{width:100%;min-width:0;margin:4px 0 0;min-height:38px;padding:7px 10px;font-size:.84rem}
.placement-swap__status{grid-column:2/-1;margin:0}
.placement-adjustments{margin:0 0 10px}
.placement-adjustments .placement-swap{padding:0;border:0}
.placement-rules{margin:9px 0 0}
.placement-rules p{max-width:72ch;margin:7px 0 0}
.placement-grid{display:grid;grid-template-columns:1fr;gap:10px;margin-top:14px}
.placement-team-card{min-width:0;padding:0;border:1px solid var(--hairline);border-radius:var(--radius-card);background:var(--surface);box-shadow:none;overflow:hidden}
.placement-team-card>summary{display:list-item;padding:13px 16px;cursor:pointer;list-style-position:inside}
.placement-team-card>summary:hover{background:var(--surface-tint)}
.placement-team-card[open]>summary{border-bottom:1px solid var(--hairline)}
.placement-team-heading{font-size:.94rem;font-weight:650;color:var(--ink)}
.placement-team-card>summary .placement-count{float:right;margin-top:1px}
.placement-team-summary{display:block;margin:3px 0 0 18px;color:var(--muted);font-size:.76rem}
.placement-team-body{padding:4px 16px 8px}
.placement-team-name{display:grid;grid-template-columns:86px minmax(0,420px);gap:10px;align-items:center;padding:10px 0 6px}
.placement-team-name label{margin:0;color:var(--muted);font-size:.72rem}
.placement-team-name input{width:100%;min-height:36px;margin:0;padding:6px 9px;font-size:.84rem;border-width:1px;border-radius:var(--radius-sm)}
.placement-warning{margin:8px 0;color:var(--warn);font-size:.78rem}
.placement-member-head,.placement-member{display:grid;grid-template-columns:minmax(170px,1.15fr) minmax(135px,.9fr) minmax(180px,1.15fr) minmax(155px,1fr) 48px;gap:9px;align-items:center;min-width:0}
.placement-member-head{padding:8px 0 5px;color:var(--muted);font:600 .61rem/1.4 var(--font-mono);letter-spacing:.07em;text-transform:uppercase}
.placement-member{border-top:1px solid var(--hairline);padding:8px 0}
.placement-member[data-placement-status="absent"],.placement-member[data-placement-status="excused"]{opacity:.72}
.placement-member[data-roster-status="inactive"]{background:var(--warn-bg);border-left:3px solid var(--warn);margin:0 -8px;padding:8px}
.placement-member[data-roster-status="inactive"] select{opacity:.62}
.placement-member__name{display:flex;align-items:center;gap:5px;flex-wrap:wrap;min-width:0;font-size:.84rem}
.placement-member__name strong{overflow-wrap:anywhere}
.placement-control{display:block;margin:0;min-width:0}
.placement-control>span{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
.placement-control select{width:100%;min-width:0;margin:0;min-height:36px;padding:6px 9px;font-size:.79rem;border-width:1px;border-radius:var(--radius-sm)}
.placement-note-toggle{margin:0;align-self:center}
.placement-note-toggle summary{width:max-content;color:var(--text-link);font-size:.76rem;font-weight:600;cursor:pointer}
.placement-note-toggle[open]{grid-column:1/-1;width:100%;padding:4px 0 2px}
.placement-note-toggle input{width:100%;margin:6px 0 0;min-height:36px;padding:6px 9px;font-size:.82rem;border-width:1px;border-radius:var(--radius-sm)}
.placement-actions{position:sticky;bottom:0;z-index:8;display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-top:14px;padding:10px 0;background:var(--bg);border-top:1px solid var(--hairline)}
.placement-actions .cab-small{margin-left:2px}
.student-layout>div{min-width:0}
.fhead .grow{min-width:0}
/* The sidebar stays a sidebar. It used to reflow into a row of buttons below
   920px — which is a tab block, the thing this admin is explicitly not meant
   to use, and it dropped the section headings that give the nav its shape.
   A browser pane docked beside an editor is routinely under 920px, so that
   was the normal case, not an edge case. Narrow the column instead. */
@media (max-width:1080px){
  .inst-layout{grid-template-columns:200px minmax(0,1fr);gap:18px}
  .side-nav button[data-pane]{font-size:.84rem;padding:7px 10px;min-height:36px;gap:10px}
  .placement-member-head{display:none}
  .placement-member{grid-template-columns:minmax(170px,1fr) repeat(3,minmax(0,1fr));align-items:end}
  .placement-member__name{grid-column:1/-1}
  .placement-control>span{position:static;width:auto;height:auto;overflow:visible;clip:auto;white-space:normal;display:block;margin:0 0 3px;color:var(--muted);font-size:.66rem}
  .placement-note-toggle{align-self:end;padding-bottom:8px}
}
@media (max-width:760px){
  .inst-layout{grid-template-columns:170px minmax(0,1fr);gap:12px}
  .side-nav button[data-pane]{font-size:.8rem;padding:7px 8px;min-height:34px;gap:8px}
  .side-nav .badge{padding:3px 6px}
  .student-layout{grid-template-columns:170px minmax(0,1fr);gap:14px}
  .student-nav button{font-size:.83rem;padding:9px 8px}
}
/* Only on an actual phone does it stack, and even then it keeps its
   headings so the grouping survives. */
@media (max-width:560px){
  .placement-heading{display:block}
  .placement-meta{justify-content:flex-start;margin-top:8px}
  .placement-settings__body,.placement-settings__control,.placement-swap{grid-template-columns:1fr}
  .placement-settings__actions{grid-column:1}
  .placement-swap__status{grid-column:1}
  .placement-swap .btn{width:100%}
  .placement-member{grid-template-columns:1fr}
  .placement-member__name{grid-column:1}
  .placement-team-name{grid-template-columns:1fr;gap:4px}
  .placement-note-toggle[open]{grid-column:1}
  .placement-actions{bottom:0}
  .placement-actions .cab-small{width:100%}
  .inst-page-head{display:block;padding-bottom:13px;margin-bottom:15px}
  .inst-page-head__actions{justify-content:flex-start;margin-top:12px}
  .inst-layout{grid-template-columns:1fr}
  .student-layout{grid-template-columns:1fr;margin-top:18px}
  .student-nav{position:static;display:flex;gap:4px;overflow-x:auto;padding:6px;scrollbar-width:thin}
  .student-nav__label{display:none}
  .student-nav button{width:auto;flex:0 0 auto;border-left:0;border-bottom:3px solid transparent;white-space:nowrap}
  .student-nav button[aria-current=true]{border-left:0;border-bottom-color:var(--cab-blue)}
  .student-nav__account{margin:0;padding:0 0 0 4px;border:0;border-left:1px solid var(--hairline)}
  .role-work{padding:18px}
  .role-work__top{display:block}
  .role-work__top .st{margin-top:10px}
  .role-guide__grid{grid-template-columns:1fr}
  .role-guide__wide{grid-column:1}
}

/* Equipment inventory groups (instructor Equipment pane). Moved from a JS-built <style> string. */
.eq-groups{display:grid;gap:8px}.eq-group{margin:0;border:1px solid var(--hairline);border-radius:var(--radius-card);background:var(--surface)}
.eq-group>summary{display:grid;grid-template-columns:minmax(220px,2fr) minmax(120px,1fr) repeat(3,minmax(64px,.55fr)) 84px;gap:16px;align-items:center;padding:16px;cursor:pointer;list-style:none}
.eq-group>summary::-webkit-details-marker{display:none}.eq-group>summary:after{content:"Details";font-size:.78rem;font-weight:400;color:var(--muted);text-align:center}
.eq-group[open]>summary:after{content:"Close"}.eq-group-name{min-width:0}.eq-group-stat{text-align:center}.eq-group-label{display:block;font-size:.72rem;color:var(--muted);font-weight:500;margin-bottom:2px}
.eq-models{border-top:1px solid var(--hairline);background:var(--surface)}.eq-model{padding:12px 16px}.eq-model+.eq-model{border-top:1px solid var(--hairline)}.eq-model--single{padding-top:4px}.eq-model-head{display:flex;align-items:baseline;justify-content:space-between;gap:16px;padding-bottom:2px}.eq-model-head .cab-small{white-space:nowrap}
.eq-units{display:grid;grid-template-columns:repeat(auto-fit,minmax(250px,1fr));column-gap:28px}
.eq-unit{min-width:0;padding:14px 0;border-bottom:1px solid var(--hairline)}.eq-unit-actions{display:flex;align-items:center;gap:14px;flex-wrap:nowrap;margin-top:8px;white-space:nowrap}.eq-unit-actions .btn{min-height:32px;padding:2px 0;border:0;background:transparent;box-shadow:none;border-radius:0;font-size:.78rem;font-weight:500}.eq-unit-actions .btn:hover{text-decoration:underline;text-underline-offset:3px;background:transparent}
@media(max-width:720px){.eq-group>summary{grid-template-columns:1fr repeat(3,48px);gap:8px;padding:14px}.eq-group-kind{display:none}.eq-group>summary:after{grid-column:1/-1;text-align:center;border-top:1px solid var(--hairline);padding-top:8px}.eq-model{padding:12px}.eq-model-head{display:block}.eq-model-head .cab-small{display:block;margin-top:2px;white-space:normal}.eq-units{grid-template-columns:1fr}}

/* ---------- draft 6 components: kicker, three-row card, card grid, account menu, bottom bar ---------- */
.kicker{display:block;font:600 11px/16px var(--font-body);letter-spacing:.1em;color:var(--cab-ink-50);text-transform:uppercase;margin:0 0 8px}
.section{margin:0 0 24px}
.inst-page-head .cab-label{display:block;margin-bottom:4px;font-size:.7rem}
.inst-page-head__actions .btn{min-height:var(--control-height)}
.tc{display:block;background:var(--surface);padding:14px 20px;min-width:0;min-height:44px;color:inherit;text-decoration:none;transition:background-color var(--dur-fast) var(--ease-standard),transform var(--dur-fast) var(--ease-standard)}
.tc[role=button]{cursor:pointer}
.tc[role=button]:hover{background:var(--surface-hover)}
.tc[role=button]:active{transform:translateY(var(--shift-press))}
.tc[aria-current=true]{box-shadow:inset 3px 0 0 var(--cab-blue)}
.tc .r1{display:flex;justify-content:space-between;align-items:center;gap:12px;margin-bottom:4px;flex-wrap:wrap}
.tc .r1 .kicker{margin:0}
.tc .r2{display:flex;justify-content:space-between;align-items:center;gap:12px;min-width:0;max-width:100%}
.tc .r2 .item{margin:0;font:600 1rem/1.5 var(--font-body);color:var(--ink);min-width:0;flex:1;text-wrap:balance;overflow-wrap:anywhere}
.tc .r2>.t{min-width:0;flex:1 1 0;overflow-wrap:anywhere}
.tc .cv{width:18px;height:18px;flex:none;stroke:var(--cab-ink-40);fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
.im{font:400 12px/18px var(--font-body);color:var(--muted);margin:2px 0 0;text-wrap:pretty}
.tc__lines{margin:10px 0 0;padding:0;list-style:none}
.tc__lines li{display:flex;gap:8px;font-size:.9rem;line-height:1.5;margin:2px 0}
.tc__lines b{flex:none;font-weight:700}
.tc__lines .ok{color:var(--ok)}
.tc__lines .no{color:var(--warn)}
.list{background:var(--surface);padding:0 20px}
.list .tc{padding:14px 0;border-top:1px solid var(--border-soft)}
.list .tc:first-child{border-top:0}
.cardgrid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:20px}
.cardgrid .tc{padding:20px 24px}
.prepcard{background:var(--surface);padding:14px 20px 18px;margin-bottom:12px}
.prepcard .r1{display:flex;justify-content:space-between;align-items:center;gap:12px;margin-bottom:6px}
.prep-item-label--done{text-decoration:line-through;color:var(--muted)}
#inst-main .tc .st{flex:none}
.acct{position:relative;display:inline-block}
.acct summary{list-style:none;display:inline-flex;align-items:center;gap:6px;cursor:pointer}
.acct summary::-webkit-details-marker{display:none}
.acct .av{width:32px;height:32px;border-radius:50%;background:rgba(255,255,255,.16);color:var(--cab-white);font:500 12px/1 var(--font-body);display:inline-flex;align-items:center;justify-content:center;letter-spacing:.02em}
.acct summary svg{width:14px;height:14px;stroke:rgba(255,255,255,.7);fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
.acct__menu{position:absolute;right:0;top:calc(100% + 8px);min-width:220px;background:var(--surface);border:1px solid var(--hairline);box-shadow:var(--shadow-raised);padding:8px 0;z-index:40;text-align:left}
.acct__who{margin:0;padding:8px 16px 10px;border-bottom:1px solid var(--border-soft);font-size:.85rem;color:var(--muted);line-height:1.4}
.acct__who strong{display:block;color:var(--ink);font-size:.95rem;font-weight:600}
.acct__item{display:block;width:100%;text-align:left;background:none;border:0;border-radius:0;padding:10px 16px;min-height:40px;font:500 .9rem/1.3 var(--font-body);color:var(--ink);cursor:pointer}
.acct__item:hover{background:var(--surface-tint)}
/* Test lane switch (FH-20260919-TEST-LANE-001): a small toggle beside the
   account menu, off on every fresh page load, its state read from
   sessionStorage only. Sits on the same Dark Blue header the account menu
   does, so its text and track use the header's white-on-blue pairing, not
   the application surface colors. */
.test-lane-switch{display:inline-flex;align-items:center;margin-right:14px}
.test-lane-toggle{display:inline-flex;align-items:center;gap:8px;background:none;border:0;border-radius:var(--radius-pill);padding:4px 6px;cursor:pointer;color:rgba(255,255,255,.82);font:500 .8rem/1 var(--font-body)}
.test-lane-toggle:hover{color:var(--cab-white)}
.test-lane-toggle__track{position:relative;display:inline-block;width:32px;height:18px;border-radius:99px;background:rgba(255,255,255,.24);transition:background var(--dur-fast) var(--ease-standard)}
.test-lane-toggle__thumb{position:absolute;top:2px;left:2px;width:14px;height:14px;border-radius:50%;background:var(--cab-white);transition:transform var(--dur-fast) var(--ease-standard)}
.test-lane-toggle.is-on .test-lane-toggle__track{background:var(--action-primary)}
.test-lane-toggle.is-on .test-lane-toggle__thumb{transform:translateX(14px)}
/* The Test lane admin panel (Settings): two accounts side by side on
   desktop, stacked on phones, the same card shape the roster panel's own
   lists already use. */
.tl-accounts{display:grid;grid-template-columns:1fr 1fr;gap:14px;margin:0 0 18px}
.tl-account{background:var(--surface-tint);border-radius:var(--radius-sm);padding:14px}
.tl-account input[readonly]{margin-top:8px}
@media (max-width:720px){
  .tl-accounts{grid-template-columns:1fr}
}
@media (max-width:720px){
  .student-load-error{align-items:flex-start;flex-direction:column}
  .student-load-error .btn{min-width:var(--control-height-phone);min-height:var(--control-height-phone)}
  .inst-layout{grid-template-columns:1fr;gap:0}
  .inst-refresh-notice{flex-direction:column;align-items:flex-start}
  .inst-refresh-notice .btn{min-height:var(--control-height-phone);align-self:flex-start}
  .side-nav{display:none}
  .side-nav.side-nav--sheet{display:flex;position:fixed;left:0;right:0;bottom:64px;top:auto;max-height:70vh;overflow:auto;background:var(--surface);border-top:1px solid var(--hairline);padding:16px 8px;z-index:30}
  /* CERT-088 phone audit finding 2: .bbar had no safe-area padding and a
     hard-coded height:64px, so on a notched/home-indicator phone (viewport-fit
     now cover, see _layout.php) the bar's own background stopped short of the
     bottom edge and the last row of buttons sat under the home indicator.
     min-height (not height) lets the bar grow by the inset instead of
     squeezing the fixed-height buttons inside it. */
  .bbar{position:fixed;left:0;right:0;bottom:0;min-height:64px;padding-bottom:env(safe-area-inset-bottom);background:var(--surface);border-top:1px solid var(--border-soft);display:grid;grid-template-columns:repeat(5,minmax(0,1fr));z-index:31}
  .bbar button{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:4px;font:600 11px/1 var(--font-body);color:var(--muted);background:none;border:0;border-radius:0;cursor:pointer;padding:0;min-height:64px}
  .bbar button[aria-current=true],.bbar button[aria-expanded=true]{color:var(--cab-blue)}
  .bbar svg{width:22px;height:22px;stroke:currentColor;fill:none;stroke-width:1.75;stroke-linecap:round;stroke-linejoin:round}
  #view-inst{padding-bottom:calc(84px + env(safe-area-inset-bottom))}
  .cardgrid{grid-template-columns:1fr}
  .inst-page-head__actions .btn{min-height:var(--control-height-phone)}
  .list{padding:0 16px}
  .tc{padding:12px 16px}
  .tc .r2--status{display:grid;grid-template-columns:minmax(0,1fr) auto}
  .tc .r2--status .item{grid-column:1/-1}
  .tc .r2--status>:not(.item):not(.cv){grid-column:1;min-width:0;max-width:100%;justify-self:start}
  .tc .r2--status>.cv{grid-column:2;grid-row:2;justify-self:end}
}

/* ---------- draft 7 layer (DESIGN-SYSTEM.md draft 7, September 6 live-build review) ----------
   Page anatomy, tables, stat cards, list rows, quick filters, slide-over
   panel, header navigation for students, the quiet footer and the preview
   strip. Every value is a token from filmhub-tokens.css. */
/* Title row: no helper sentence under a title, ever. */
.inst-page-head p,.student-pane__head p{display:none}
.inst-page-head{border-bottom:0;padding:0;margin:0 0 20px}
.inst-page-head h2,.student-pane__head h2{color:var(--cab-blue-dark)}
/* Instructor preview: a 32 px peach strip that never outranks the page. */
.fh-app #preview-banner{background:var(--cab-peach);border:0;border-radius:0;padding:6px 16px;min-height:32px;font-size:var(--type-meta);line-height:20px;color:var(--ink);margin:0 0 20px!important}
.fh-app #preview-banner .btn{background:none;border:0;color:var(--cab-blue-dark);padding:0;min-height:0;font-weight:500}
.fh-app #preview-banner .btn:hover{color:var(--cab-blue)}
/* Footer: one quiet line on application pages. */
.fh-app .site-footer{background:transparent;border-top:1px solid var(--border-soft);color:var(--muted);margin-top:0}
.fh-app .site-footer .wrap{padding:20px}
.fh-app .site-footer p{font-size:var(--type-meta);line-height:20px;color:var(--muted);margin:0}
.fh-app .site-footer a{color:var(--cab-blue-dark);text-decoration:none;font-weight:500}
.fh-app .site-footer a:hover{color:var(--cab-blue)}
.foot-line{display:flex;flex-wrap:wrap;gap:6px 14px;align-items:center;justify-content:space-between}
.foot-line span{display:inline-flex;flex-wrap:wrap;gap:6px 14px}
/* Surfaces: white without outlines. */
.fh-app .card,.fh-app #inst-main .card{border:0;box-shadow:none;padding:20px 24px}
.fh-app .card--tint,.fh-app #inst-main .card--tint{background:var(--surface-muted);border:0}
.fh-app .detail-panel{border:0;box-shadow:none}
.fh-app .prod-card{border:0}
.fh-app .opp-list{border:0}
.fh-app fieldset{border:0;padding:0;margin:20px 0 0;background:transparent}
.fh-app legend{padding:0;font:600 11px/16px var(--font-body);letter-spacing:.1em;text-transform:uppercase;color:var(--cab-ink-50)}
.fh-app label{font:500 13px/20px var(--font-body);margin:14px 0 4px}
/* Tables: white surface, no outer border, no vertical lines, the row is the link. */
.fh-app table.data{background:var(--surface);font-size:.9375rem}
.fh-app table.data th{padding:10px 16px;font:500 13px/20px var(--font-body);letter-spacing:0;text-transform:none;color:var(--muted);border-bottom:1px solid var(--hairline)}
.fh-app table.data th .th-sort{font:inherit;color:inherit;letter-spacing:0;text-transform:none}
.fh-app table.data td{padding:15px 16px;border-bottom:1px solid var(--border-soft);vertical-align:middle}
.fh-app table.data tbody tr:last-child td{border-bottom:0}
.fh-app table.data tbody td:first-child{font-weight:700;color:var(--ink)}
.fh-app table.data tbody tr:hover{background:var(--surface-hover)}
.fh-app table.data td.num,.fh-app table.data th.num{text-align:right}
.fh-app table.data td .btn{white-space:nowrap}
.fh-app .roster-tbl th:last-child,.fh-app .roster-tbl td:last-child{border-left:0}
.fh-app tr[role=button]{cursor:pointer}
.fh-app td.cv-cell{width:32px;padding-right:12px}
.fh-app td.cv-cell .cv{width:18px;height:18px;stroke:var(--cab-ink-40);fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;display:block}
/* KPI stat cards: the number large, the label under it, a chevron at the right. */
.fh-app .kpi-row{gap:16px;grid-template-columns:repeat(auto-fit,minmax(160px,1fr))}
.fh-app .kpi,.fh-app #inst-main .kpi{position:relative;display:flex;flex-direction:column;border:0;border-radius:0;box-shadow:none;background:var(--surface);padding:18px 20px 16px;min-height:0;transition:background-color var(--dur-fast) var(--ease-standard),transform var(--dur-fast) var(--ease-standard)}
.fh-app .kpi .k-value,.fh-app #inst-main .kpi .k-value{order:1;font:700 28px/32px var(--font-body);color:var(--cab-blue-dark);margin:0;letter-spacing:-.01em;font-variant-numeric:tabular-nums}
.fh-app .kpi .k-value--status{font:500 15px/22px var(--font-body)}
.fh-app .kpi .k-value--date{font:600 16px/24px var(--font-body)}
.fh-app .kpi .k-label{order:2;margin:2px 0 0;font:400 13px/20px var(--font-body);color:var(--muted);letter-spacing:0;text-transform:none}
.fh-app .kpi .k-sub{order:3;margin:2px 0 0;font-size:12px;line-height:18px;color:var(--muted)}
.fh-app .kpi.k-good .k-value{color:var(--ok)}
.fh-app .kpi.k-warn .k-value{color:var(--warn)}
.fh-app .kpi[role=button]{cursor:pointer;padding-right:44px}
.fh-app .kpi[role=button]:hover{background:var(--surface-hover)}
.fh-app .kpi[role=button]:active{transform:translateY(var(--shift-press))}
.fh-app .kpi[role=button]::after{content:"";position:absolute;right:20px;top:50%;width:8px;height:8px;margin-top:-5px;border-right:2px solid var(--cab-ink-40);border-bottom:2px solid var(--cab-ink-40);transform:rotate(-45deg)}
.fh-app .kpi[aria-pressed=true]{box-shadow:inset 3px 0 0 var(--cab-blue)}
/* List rows: 16 px rhythm, soft dividers, at most one pill and one quiet action. */
.fh-app .doc-row,.fh-app #inst-main .doc-row{background:transparent;border:0;border-top:1px solid var(--border-soft);border-radius:0;padding:14px 0;margin:0}
.fh-app .doc-row:first-child{border-top:0}
.fh-app .doc-row--req{border-left:0;box-shadow:inset 3px 0 0 var(--cab-blue-dark);padding-left:14px}
.fh-app .drow-tag{font:400 12px/18px var(--font-body);border:0;border-radius:0;padding:0;color:var(--muted);letter-spacing:0;text-transform:none;white-space:normal}
.fh-app .cab-caption{font:400 12px/18px var(--font-body);color:var(--muted);letter-spacing:0}
.fh-app .recent-list{border-top:0;margin-top:0;padding-top:0}
/* Folds render flat: no box, the summary is a section title with a quiet Show or Hide. */
.fh-app .fold,.fh-app #inst-main .fold{border:0;border-radius:0;background:transparent;box-shadow:none;margin-bottom:20px;overflow:visible}
.fh-app .fold>summary,.fh-app #inst-main .fold>summary{padding:6px 0;background:transparent;font:600 11px/16px var(--font-body);letter-spacing:.1em;text-transform:uppercase;color:var(--cab-ink-50);gap:10px}
.fh-app .fold>summary:hover,.fh-app #inst-main .fold>summary:hover{background:transparent;color:var(--cab-blue-dark)}
.fh-app .fold>summary::after,.fh-app #inst-main .fold>summary::after{content:"Show";width:auto;height:auto;border:0;transform:none;margin-left:8px;font:500 12px/16px var(--font-body);letter-spacing:0;text-transform:none;color:var(--cab-blue-dark);transition:none}
.fh-app .fold[open]>summary::after,.fh-app #inst-main .fold[open]>summary::after{content:"Hide";transform:none}
.fh-app .fold[open]>summary,.fh-app #inst-main .fold[open]>summary{border-bottom:0}
.fh-app .fold__body,.fh-app #inst-main .fold__body{padding:8px 0 0}
.fh-app .fold__pill{font:500 12px/16px var(--font-body);letter-spacing:0;text-transform:none;background:var(--status-neutral-bg);color:var(--status-neutral-text);padding:3px 8px;border-radius:var(--radius-pill)}
.fh-app .fold__count{font:500 12px/16px var(--font-body);letter-spacing:0;text-transform:none;background:var(--status-neutral-bg);color:var(--status-neutral-text);padding:3px 8px;border-radius:var(--radius-pill)}
/* Quick filters: 30 px pills, the active one Dark Blue. Also the legacy chips row. */
.qf,.fh-app .chips{display:flex;gap:8px;flex-wrap:wrap;align-items:center;margin:0 0 16px}
.qf__b,.fh-app .chips button{font:500 13px/20px var(--font-body);min-height:30px;padding:4px 12px;border:1px solid var(--hairline);border-radius:var(--radius-pill);background:var(--surface);color:var(--ink);cursor:pointer;letter-spacing:0;transition:background-color var(--dur-fast) var(--ease-standard),color var(--dur-fast) var(--ease-standard),border-color var(--dur-fast) var(--ease-standard)}
.qf__b:hover,.fh-app .chips button:hover{border-color:var(--cab-blue-dark);color:var(--cab-blue-dark)}
.qf__b[aria-pressed=true],.fh-app .chips button[aria-pressed=true]{background:var(--cab-blue-dark);color:var(--cab-white);border-color:var(--cab-blue-dark)}
.qf__n{opacity:.7;margin-left:2px}
.qf .qf__search{margin-left:auto;min-width:200px;max-width:280px;min-height:36px;padding:6px 12px}
/* Always-visible filter selects (Inventory's course/owner/status/availability,
   Out now's student/production/item): the same qfilters row a pill and the
   search box already sit in, never a "More filters" panel. */
.qf__sel{font:500 13px/20px var(--font-body);min-height:34px;padding:5px 10px;border:1px solid var(--hairline);border-radius:var(--radius-sm);background:var(--surface);color:var(--ink);cursor:pointer;width:auto;flex:0 1 200px;min-width:160px;max-width:220px}
.qf__sel:hover{border-color:var(--cab-blue-dark)}
/* Context strip: selectors and filters in one row. */
.ctx{display:flex;align-items:flex-end;gap:12px 16px;flex-wrap:wrap;margin:0 0 16px}
.ctx label{margin:0 0 4px}
.ctx .phase-pick{max-width:230px}
.ctx__sum{font:400 13px/20px var(--font-body);color:var(--muted);align-self:center}
/* Tabs: one row, sans bold 16, Primary Blue underline. */
.fh-app .subtabs{gap:0;border-bottom:1px solid var(--hairline);margin:0 0 20px}
.fh-app .subtab{font:700 16px/24px var(--font-body);color:var(--muted);padding:10px 2px;margin:0 22px -1px 0;border-bottom:2px solid transparent;border-radius:0;letter-spacing:0}
.fh-app .subtab:hover{background:transparent;color:var(--cab-blue-dark)}
.fh-app .subtab[aria-selected=true]{color:var(--cab-blue-dark);border-bottom-color:var(--cab-blue)}
.fh-app .subtab .drow-tag{font:500 12px/16px var(--font-body);background:var(--status-neutral-bg);color:var(--status-neutral-text);padding:2px 7px;border-radius:var(--radius-pill);margin-left:6px}
/* Slide-over panel: 520 px from the right over a Dark Blue scrim. */
.scrim{position:fixed;inset:0;background:var(--cab-blue-dark);opacity:.28;z-index:60}
.scrim[hidden]{display:none}
.panel{position:fixed;top:0;right:0;bottom:0;width:520px;max-width:100%;background:var(--surface);border-left:1px solid var(--hairline);box-shadow:var(--shadow-overlay);z-index:61;display:flex;flex-direction:column;animation:panel-in var(--dur-slow) var(--ease-out)}
.panel[hidden]{display:none}
@keyframes panel-in{from{transform:translateX(24px);opacity:0}to{transform:none;opacity:1}}
.panel__head{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;padding:28px 32px 16px}
.panel__copy{min-width:0}
.panel__copy .kicker{margin-bottom:4px}
.panel__copy .kicker[hidden]{display:none}
.panel__head h2{margin:0;font-size:24px;line-height:32px;color:var(--cab-blue-dark);letter-spacing:-.01em}
.panel__close{flex:none;background:none;border:0;color:var(--cab-blue-dark);font:500 13px/20px var(--font-body);padding:6px 0;cursor:pointer;min-height:32px}
.panel__close:hover{color:var(--cab-blue)}
/* min-width:0 matters as much as the existing min-height:0 here: without it,
   a flex item defaults to min-width:auto, so a wide child (a table whose
   content sets a wider intrinsic minimum, e.g. crew-table or rel-table)
   stretches panel__body itself past the fixed-width .panel instead of
   scrolling inside it, and .panel's own default overflow:visible then lets
   that excess paint past the panel's right edge, off past the viewport,
   invisible to document.scrollWidth because .panel is position:fixed and
   out of normal flow. Found measuring the production panel at 375 CSS px
   (the hard rule on actions, Gabe, 19 Sep 2026). */
.panel__body{flex:1 1 auto;overflow:auto;padding:0 32px 24px;min-height:0;min-width:0}
.panel__body>.kicker{margin-top:20px}
.panel__body .list{padding:0}
.panel__actions{display:flex;gap:8px;flex-wrap:wrap;align-items:center;padding:16px 32px 24px;border-top:1px solid var(--border-soft)}
.panel__actions[hidden]{display:none}
.panel__actions .grow{min-width:0}
body.panel-open{overflow:hidden}
@media (max-width:720px){.panel{width:100%;border-left:0}.panel__head{padding:20px 20px 12px}.panel__body{padding:0 20px 20px}.panel__actions{padding:12px 20px 20px}}
/* Student shell: navigation as one row of links in the header on desktop, a bottom bar on phones. */
.hdr-nav{display:flex;align-items:center;gap:4px;margin-left:18px;min-width:0;overflow:hidden}
.hdr-nav[hidden]{display:none}
.hdr-nav .student-nav{position:static;display:flex;gap:2px;background:transparent;border:0;border-radius:0;box-shadow:none;padding:0;margin:0}
.hdr-nav .student-nav__label{display:none}
.hdr-nav .student-nav button{width:auto;min-height:40px;padding:8px 12px;border:0;border-radius:0;background:transparent;color:rgba(255,255,255,.82);font:500 14px/20px var(--font-body);white-space:nowrap;border-bottom:2px solid transparent;cursor:pointer;transition:color var(--dur-fast) var(--ease-standard)}
.hdr-nav .student-nav button:hover{background:transparent;color:var(--cab-white)}
.hdr-nav .student-nav button[aria-current=true]{background:transparent;color:var(--cab-white);border-bottom-color:var(--cab-blue-light);font-weight:700}
.hdr-nav .student-nav__account{margin:0;padding:0;border:0}
.hdr-nav:not([hidden])~.portal-header__back{display:none}
.student-layout{display:block;margin-top:0}
.student-layout>.student-nav{display:none}
#home-bbar{display:none}
#home-sheet[hidden]{display:none}
.fh-app .student-pane__head{margin-bottom:20px}
/* Student Today: the week as mono label, hero announcement cards, the meter. */
.today-head{margin:0 0 20px}
.today-head h2{margin:0;font-size:32px;line-height:40px;letter-spacing:-.015em;color:var(--cab-blue-dark)}
.today-head .kicker{margin-bottom:2px}
.hero{position:relative;background:var(--surface);box-shadow:inset 4px 0 0 var(--cab-blue);padding:18px 48px 18px 28px;margin:0 0 12px;display:block}
.hero:has(.hero__thumb){padding-right:120px}
.hero__thumb{position:absolute;right:24px;top:18px;width:72px;height:72px;object-fit:cover}
.hero .r1{display:flex;gap:12px;align-items:center;margin-bottom:2px}
.hero .r1 .kicker{margin:0}
.hero .r1 .im{margin:0}
.hero__title{margin:0;font:600 16px/24px var(--font-body);color:var(--ink);text-wrap:balance}
.hero__body{margin:4px 0 0;font:400 15px/22px var(--font-body);color:var(--ink);max-width:var(--reading-max);overflow:hidden;display:-webkit-box;-webkit-line-clamp:1;-webkit-box-orient:vertical}
/* Hard rule on actions, 19 Sep 2026: at most the one open-link control plus
   the quiet Read text action, held to one line at every width. */
.hero__acts{display:flex;flex-wrap:nowrap;align-items:center;gap:14px;margin-top:10px;min-width:0}
.hero__acts>.btn,.hero__acts>.hero__read{flex:none;white-space:nowrap}
.hero__read{background:none;border:0;padding:0;color:var(--cab-blue-dark);font:500 13px/20px var(--font-body);cursor:pointer;min-height:24px}
.hero__read:hover{color:var(--cab-blue)}
.hero__x{position:absolute;top:10px;right:12px;width:28px;height:28px;background:none;border:0;color:var(--cab-ink-45);font:400 20px/1 var(--font-body);cursor:pointer;border-radius:var(--radius-pill)}
.hero__x:hover{color:var(--ink);background:var(--surface-muted)}
.hero--dark{background:var(--cab-blue-dark);color:var(--cab-white);box-shadow:none;padding:20px 24px;display:block}
.hero--dark .kicker{color:rgba(255,255,255,.7)}
.hero--dark .hero__title{color:var(--cab-white);font-size:20px;line-height:28px}
.hero--dark .im{color:rgba(255,255,255,.75)}
.hero--dark .btn{margin-top:14px;min-height:var(--control-height-hero);padding:8px 18px}
.meter{background:var(--surface);padding:18px 24px;margin:0 0 12px}
.meter .r1{display:flex;justify-content:space-between;align-items:center;gap:12px;margin-bottom:4px}
.meter .r1 .kicker{margin:0}
.meter__title{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin:0 0 14px;font:600 16px/24px var(--font-body);color:var(--ink)}
.meter__track{position:relative;height:2px;background:var(--hairline);margin:14px 6px 8px}
.meter__fill{position:absolute;left:0;top:0;height:2px;background:var(--cab-blue)}
.meter__node{position:absolute;top:50%;width:8px;height:8px;margin:-4px 0 0 -4px;border-radius:50%;background:var(--cab-blue)}
.meter__node--now{width:12px;height:12px;margin:-6px 0 0 -6px}
.meter__node--due{background:var(--surface);border:2px solid var(--cab-blue);box-sizing:border-box}
.meter__ends{display:flex;justify-content:space-between;font:400 12px/18px var(--font-body);color:var(--muted)}
.fh-app .list .tc .btn{flex:none}
.fh-app .tc .r2 .st{flex:none}
.section-head{display:flex;align-items:baseline;justify-content:space-between;gap:12px;margin:0 0 8px}
.section-head .kicker{margin:0}
.section-head .quiet{background:none;border:0;padding:0;color:var(--cab-blue-dark);font:500 13px/20px var(--font-body);cursor:pointer}
.section-head .quiet:hover{color:var(--cab-blue)}
.empty{margin:0;padding:12px 0;font:400 13px/20px var(--font-body);color:var(--muted)}
@media (max-width:720px){
  .hdr-nav{display:none!important}
  #view-home{padding-bottom:84px}
  #home-bbar{position:fixed;left:0;right:0;bottom:0;height:64px;background:var(--surface);border-top:1px solid var(--border-soft);display:grid;grid-template-columns:repeat(5,minmax(0,1fr));z-index:31}
  #home-bbar button{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:4px;font:600 11px/1 var(--font-body);color:var(--muted);background:none;border:0;border-radius:0;cursor:pointer;padding:0;min-height:64px}
  #home-bbar button[aria-current=true],#home-bbar button[aria-expanded=true]{color:var(--cab-blue)}
  #home-bbar svg{width:22px;height:22px;stroke:currentColor;fill:none;stroke-width:1.75;stroke-linecap:round;stroke-linejoin:round}
  #home-sheet{position:fixed;left:0;right:0;bottom:64px;background:var(--surface);border-top:1px solid var(--hairline);padding:12px 8px;z-index:30;display:flex;flex-direction:column}
  #home-sheet button{display:flex;align-items:center;gap:12px;width:100%;text-align:left;font:500 15px/22px var(--font-body);background:none;border:0;padding:12px 16px;min-height:48px;color:var(--ink);cursor:pointer}
  #home-sheet button[aria-current=true]{color:var(--cab-blue-dark);font-weight:700}
  .today-head h2{font-size:28px;line-height:36px}
  .hero{padding:16px 40px 16px 22px}
  .hero:has(.hero__thumb){padding-right:100px}
  .hero__thumb{right:16px;top:16px;width:56px;height:56px}
  .fh-app .kpi-row{grid-template-columns:repeat(2,minmax(0,1fr));gap:10px}
  .fh-app .kpi,.fh-app #inst-main .kpi{padding:14px 16px 12px}
  .fh-app .kpi[role=button]{padding-right:36px}
  .fh-app .kpi .k-value,.fh-app #inst-main .kpi .k-value{font-size:24px;line-height:28px}
  .fh-app table.data th,.fh-app table.data td{padding-left:12px;padding-right:12px}
  .qf .qf__search{margin-left:0;min-width:0;width:100%;max-width:none}
  .qf .qf__sel{flex:1 1 140px}
}
/* ---------- Announcements and Forms, instructor (draft 7 pages) ----------
   Filters and selects share the context strip, a card carries one quiet
   more control, the composer and the responses render inside the panel. */
.ctx .qf{margin:0}
.ctx>.grow{flex:0 1 200px;min-width:0}
.empty:empty{display:none}
.tc .r1__end{display:inline-flex;align-items:center;gap:8px;flex:none}
.tc .more{background:none;border:0;border-radius:var(--radius-pill);width:28px;height:28px;padding:0;font:400 16px/1 var(--font-body);color:var(--cab-ink-45);cursor:pointer;transition:background-color var(--dur-fast) var(--ease-standard),color var(--dur-fast) var(--ease-standard)}
.tc .more:hover{color:var(--ink);background:var(--surface-muted)}
.panel .opp-editor{border:0;border-radius:0;padding:0;max-width:none}
.panel .opp-editor>.kicker{margin:24px 0 4px}
.opp-body{margin:12px 0;white-space:pre-line;max-width:var(--reading-max);font:400 15px/22px var(--font-body);color:var(--ink);text-wrap:pretty}
.opp-links{margin:12px 0}
.panel .list .tc{padding:12px 0}
.panel .list .tc .r1{margin-bottom:2px}
.panel .list .tc .r1 .im{margin:0}
.resp-acts{margin-top:8px}
.resp-acts select{min-height:var(--control-height);width:auto}

/* ---------- Documents library and Equipment catalog (instructor), draft 7 ----------
   Type icons on document cards, the quiet "more" control on a card or a unit
   row, quantity fields in the check-out panel, and the phone rule that turns
   the Out now and Returns tables into lists. Tokens only. */
.dk{width:16px;height:16px;flex:none;stroke:currentColor;fill:none;stroke-width:1.75;stroke-linecap:round;stroke-linejoin:round;vertical-align:-3px;margin-right:6px}
.doc-card .r1 .kicker{display:inline-flex;align-items:center}
.ctx>.qf{flex:1 1 auto;margin:0}
.doc-card--off .item{color:var(--text-muted)}
.tc .more{flex:none;width:32px;height:32px;margin:-4px -8px -4px 0;padding:0;background:none;border:0;border-radius:var(--radius-pill);color:var(--cab-ink-50);font:400 20px/1 var(--font-sans);cursor:pointer;display:inline-flex;align-items:center;justify-content:center}
.tc .more:hover{background:var(--surface-hover);color:var(--cab-blue-dark)}
.tc .more:focus-visible{outline:2px solid var(--cab-blue-dark);outline-offset:2px}
.tc .r2 .sq{width:72px;flex:none;margin:0;min-height:36px;text-align:right}
.unit-row[data-off] .item{color:var(--text-muted)}
.panel__body .im .st{vertical-align:middle}
.panel__body .im+.list{margin-top:8px}
.panel__body .measure{white-space:pre-wrap}
@media (max-width:720px){
  .eq-tbl thead{display:none}
  .eq-tbl tr{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;border-bottom:1px solid var(--border-soft);padding:12px 0}
  .eq-tbl tr:last-child{border-bottom:0}
  .fh-app .eq-tbl td{display:block;padding:0;border:0}
  .fh-app .eq-tbl td:nth-child(n+3):not(.cv-cell){display:none}
  .fh-app .eq-tbl td.num{text-align:left}
  .fh-app .eq-tbl td.cv-cell{grid-column:2;grid-row:1/span 2;width:auto;padding:0}
}
/* Out now: Who never wraps a name onto a second line; Item, the longest
   text in the row, is the column left to wrap instead. */
.eq-out td.who-cell{white-space:nowrap}
/* Out now and Returns own their own phone layout, since the .eq-tbl rules
   above only ever fit Inventory's Course/Total/Available columns: under
   720px they hid every column past the second (.eq-tbl td:nth-child(n+3)),
   so Who, Out and Due were simply invisible on a phone. Each td here
   carries its real label in data-label, read with attr(), so a card shows
   every column with the correct name regardless of how many columns a
   given table has (Out now: five; Returns: three). */
@media (max-width:720px){
  .eq-out thead{display:none}
  .eq-out,.eq-out tbody{display:block;width:100%}
  .eq-out tr.grp-row{display:block;padding:16px 0 2px}
  .eq-out tr.grp-row:first-child{padding-top:0}
  .eq-out tr.grp-row td{display:block;padding:0;border:0}
  .eq-out tr:not(.grp-row){display:grid;grid-template-columns:minmax(0,1fr) auto;column-gap:10px;align-items:start;border-bottom:1px solid var(--border-soft);padding:12px 0}
  .fh-app .eq-out td{display:block;padding:2px 0;border:0}
  .fh-app .eq-out td[data-label]::before{content:attr(data-label) " ";display:block;font:600 .66rem/1.4 var(--font-mono);letter-spacing:.08em;text-transform:uppercase;color:var(--muted)}
  .fh-app .eq-out td.num{text-align:left}
  .fh-app .eq-out td.cv-cell{grid-column:2;grid-row:1/-1;width:auto;padding:0}
  .fh-app .eq-out td.who-cell{white-space:normal}
}

/* ---------- Attendance, Roster and Reports (draft 7 pages) ----------
   The keyboard hint bar, the one-line attendance row with its state pill,
   the roster email cell and the student record in the panel. Tokens only. */
.keyhint{margin:0 0 12px;font:400 12px/18px var(--font-body);color:var(--muted)}
.keyhint kbd{font:500 11px/1 var(--font-mono);background:var(--surface-tint);border:1px solid var(--hairline);border-radius:var(--radius-sm);padding:2px 5px;color:var(--ink)}
.att-list{margin-bottom:24px}
.att-row{display:flex;align-items:center;gap:12px;flex-wrap:wrap}
.att-row .item{margin:0;flex:none;font:600 1rem/1.5 var(--font-body);color:var(--ink);min-width:0}
.att-row .im{margin:0;flex:1 1 auto;min-width:0}
.att-row .st{flex:none}
.att-more{flex:none;margin-left:auto;width:28px;height:28px;background:none;border:0;border-radius:var(--radius-pill);color:var(--cab-ink-45);font:400 18px/1 var(--font-body);cursor:pointer;padding:0}
.att-more:hover{color:var(--ink);background:var(--surface-muted)}
.att-row--wait .item{color:var(--muted)}
.fh-app .att-row:focus-visible{outline:2px solid var(--cab-blue-dark);outline-offset:2px}
.roster-email{max-width:220px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--muted);font-size:var(--type-meta)}
.fh-app table.data td .im{margin:0}
.fh-app table.data td .empty{padding:0}
.rec-id{display:flex;gap:14px;align-items:center;margin:4px 0 8px}
.rec-av{flex:none;width:44px;height:44px;border-radius:50%;background:var(--cab-blue-dark);color:var(--cab-white);font:500 15px/1 var(--font-body);display:inline-flex;align-items:center;justify-content:center;letter-spacing:.02em}
.rec-pills{display:flex;gap:6px;flex-wrap:wrap;margin-top:6px}
.rec-noterow{display:flex;gap:10px;align-items:center;margin:8px 0 12px}
.rec-note{margin:2px 0 0;white-space:pre-wrap;font-size:.95rem;line-height:1.5}
.rec-remove{color:var(--warn);border-color:var(--warn)}
@media (max-width:720px){
  .att-row .im{flex-basis:100%;order:3}
}
#ipane-attend .kpi-row,#ipane-students .kpi-row{grid-template-columns:repeat(5,minmax(0,1fr))}
@media (max-width:720px){#ipane-attend .kpi-row,#ipane-students .kpi-row{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media (max-width:720px){.fh-app .site-header .portal-header__back{display:none}}

/* ---------- draft 8 layer (September 6 round 8): collapsed icon sidebar, quieter scale, canvas, motion ---------- */
/* Titles, kickers, numbers and controls downsized. */
.fh-app .today-head h2,.fh-app .panel__head h2{font-size:22px;line-height:28px}
.fh-app .kicker,.fh-app .cab-label,.fh-app .nav-group__name,.fh-app .inst-page-head .cab-label{font:600 10px/16px var(--font-body);letter-spacing:.1em;text-transform:uppercase;color:var(--cab-ink-50)}
.fh-app .kpi .k-value,.fh-app #inst-main .kpi .k-value{font:500 22px/28px var(--font-body);font-variant-numeric:tabular-nums;letter-spacing:0}
.fh-app .kpi,.fh-app #inst-main .kpi{padding:14px 18px 12px}
.fh-app .kpi[role=button]{padding-right:18px}
.fh-app .kpi[role=button]::after{display:none}
.fh-app .kpi[role=button]:hover{background:var(--surface-muted)}
.fh-app .kpi[aria-pressed=true]{background:var(--surface-muted);box-shadow:inset 3px 0 0 var(--cab-blue)}
.fh-app :is(input[type=text],input[type=email],input[type=password],input[type=tel],input[type=date],input[type=time],input[type=number],input[type=url],input[type=search],select){min-height:var(--field-height);padding:7px 12px;font:400 var(--type-support)/20px var(--font-body)}
.fh-app .qf .qf__search,.fh-app .keyrow .qf__search{min-height:var(--field-height)}
.fh-app .btn{min-height:var(--control-height);padding:6px 16px;transition:background-color var(--dur-fast) var(--ease-standard),color var(--dur-fast) var(--ease-standard),border-color var(--dur-fast) var(--ease-standard),transform var(--dur-fast) var(--ease-out)}
.fh-app .btn-secondary{background:var(--cab-blue)}
.fh-app .btn-secondary:hover{background:var(--cab-blue-dark)}
.fh-app .btn-ghost{color:var(--cab-ink-66)}
.fh-app .btn-ghost:hover{background:var(--surface-hover);color:var(--cab-blue-dark);border-color:var(--hairline)}
.keyrow{display:flex;align-items:center;justify-content:space-between;gap:16px;flex-wrap:wrap;margin:0 0 12px}
.keyrow .keyhint{margin:0}
.keyrow .qf__search{margin-left:auto;min-width:200px;max-width:280px}
/* Canvas and cards: white on Extra Light Blue. */
.fh-app .list,.fh-app .tc,.fh-app .card,.fh-app .kpi,.fh-app .meter,.fh-app .hero,.fh-app .prepcard,.fh-app table.data,.fh-app .fold__body>.list{background:var(--surface)}
.fh-app .side-nav button[data-pane]:hover{background:var(--surface)}
/* Motion: hover fills, chevron slide, 1 px press, staggered panes, the phone sheet from the bottom. */
.fh-app .tc .cv,.fh-app td.cv-cell .cv{transition:transform var(--dur-fast) var(--ease-standard)}
.fh-app .tc[role=button]:hover .cv,.fh-app tr[role=button]:hover .cv{transform:translateX(2px)}
.fh-app tr[role=button]{transition:background-color var(--dur-fast) var(--ease-standard)}
.fh-app .kpi[role=button]:active,.fh-app tr[role=button]:active{transform:translateY(var(--shift-press))}
@keyframes rise{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
.ipane.in>*,.student-pane.in>*{animation:rise var(--dur-base) var(--ease-out) both}
.ipane.in>*:nth-child(2),.student-pane.in>*:nth-child(2){animation-delay:40ms}
.ipane.in>*:nth-child(3),.student-pane.in>*:nth-child(3){animation-delay:80ms}
.ipane.in>*:nth-child(4),.student-pane.in>*:nth-child(4){animation-delay:120ms}
.ipane.in>*:nth-child(5),.student-pane.in>*:nth-child(5){animation-delay:160ms}
.ipane.in>*:nth-child(6),.student-pane.in>*:nth-child(6){animation-delay:200ms}
.ipane.in>*:nth-child(7),.student-pane.in>*:nth-child(7){animation-delay:240ms}
.ipane.in>*:nth-child(n+8),.student-pane.in>*:nth-child(n+8){animation-delay:280ms}
@keyframes panel-up{from{transform:translateY(24px);opacity:0}to{transform:none;opacity:1}}
/* Sidebar: a 64 px icon bar that expands to 240 px over the canvas on hover, focus or tap. */
@media (min-width:721px){
  .inst-layout{grid-template-columns:64px minmax(0,1fr);gap:20px}
  .side-nav{width:64px;overflow:hidden;background:var(--surface);z-index:35;transition:width var(--dur-base) var(--ease-out),box-shadow var(--dur-base) var(--ease-out);padding:8px 0}
  .side-nav .nav-group{margin-bottom:8px}
  .side-nav .nav-group__name{height:0;overflow:hidden;padding:0 16px;opacity:0;transition:opacity var(--dur-base) var(--ease-out)}
  .side-nav button[data-pane]{padding:10px 0 10px 21px;gap:14px;white-space:nowrap;min-height:40px;border-left-width:3px}
  .side-nav button[data-pane] svg{width:20px;height:20px;flex:none}
  .side-nav button[data-pane] span{opacity:0;transition:opacity var(--dur-base) var(--ease-out)}
  .side-nav button[data-pane] .badge{position:absolute;left:34px;top:6px;padding:2px 5px;opacity:1}
  .side-nav button[data-pane]{position:relative}
  .side-nav:hover,.side-nav:focus-within,.side-nav.side-nav--open{width:240px;box-shadow:var(--shadow-raised)}
  .side-nav:hover .nav-group__name,.side-nav:focus-within .nav-group__name,.side-nav.side-nav--open .nav-group__name{height:auto;padding:6px 16px;opacity:1}
  .side-nav:hover button[data-pane] span,.side-nav:focus-within button[data-pane] span,.side-nav.side-nav--open button[data-pane] span{opacity:1}
  .side-nav:hover button[data-pane] .badge,.side-nav:focus-within button[data-pane] .badge,.side-nav.side-nav--open button[data-pane] .badge{position:static;padding:4px 8px;margin-left:auto}
}
@media (max-width:720px){
  .panel{top:auto;max-height:92vh;border-left:0;border-top:1px solid var(--hairline);animation:panel-up var(--dur-slow) var(--ease-out)}
}
@media (max-width:720px){.keyrow .qf__search{margin-left:0;max-width:none;width:100%}}

/* ---------- draft 9 layer (September 6 emergency notes): canvas, card borders, steady sidebar, one list card ---------- */
.fh-app .list,.fh-app .card,.fh-app .kpi,.fh-app .meter,.fh-app .hero,.fh-app .prepcard,.fh-app .tbl-wrap,.fh-app .cardgrid>.tc,.fh-app .role-work,.fh-app .opp-list,.fh-app .prod-card{border:1px solid var(--hairline)}
.fh-app .list .tc,.fh-app .cardgrid .tc .tc{border-left:0;border-right:0}
.fh-app .list .tc{border-top:1px solid var(--border-soft)}
.fh-app .list .tc:first-child{border-top:0}
.fh-app .list .tc[role=button]:hover,.fh-app .att-list .att-row:hover{background:var(--surface-hover)}
.fh-app .tbl-wrap table.data{background:var(--surface)}
.fh-app .fold__body .list,.fh-app .panel__body .list{border:0}
/* Sidebar: fixed padding and a reserved 3 px border, so hover changes color only. */
.fh-app .side-nav button[data-pane]{border-left:3px solid transparent;padding:8px 12px 8px 11px;transition:background-color var(--dur-fast) var(--ease-standard),border-color var(--dur-fast) var(--ease-standard),color var(--dur-fast) var(--ease-standard)}
.fh-app .side-nav button[data-pane]:hover{background:var(--surface-brand-tint);border-left-color:var(--cab-blue);color:var(--cab-blue-dark)}
.fh-app .side-nav button[data-pane][aria-current=true]{background:var(--cab-blue);color:var(--cab-white);border-left-color:var(--cab-blue-dark)}
@media (min-width:721px){
  .fh-app .side-nav button[data-pane]{padding:10px 0 10px 19px}
  .fh-app .side-nav{border:1px solid var(--hairline);transition:width var(--dur-base) var(--ease-out)}
  .fh-app .side-nav:hover,.fh-app .side-nav:focus-within,.fh-app .side-nav.side-nav--open{box-shadow:none}
}
/* The class-night pages: one card holds the summary strip, the hint row and the list. */
#ipane-attend .kpi-row,#ipane-students .kpi-row{gap:0;background:var(--surface);border:1px solid var(--hairline);border-bottom:0;margin-bottom:0}
#ipane-attend .kpi-row .kpi,#ipane-students .kpi-row .kpi{border:0;border-right:1px solid var(--border-soft);padding:12px 16px 10px}
#ipane-attend .kpi-row .kpi:last-child,#ipane-students .kpi-row .kpi:last-child{border-right:0}
#ipane-attend .keyrow,#ipane-students .keyrow{background:var(--surface);border:1px solid var(--hairline);border-bottom:1px solid var(--border-soft);margin:0;padding:10px 16px}
#ipane-attend .att-list,#ipane-students .tbl-wrap{border-top:0;margin-top:0}
#ipane-attend .att-list{padding:0 16px}
@media (max-width:720px){
  #ipane-attend .kpi-row .kpi:nth-child(2n){border-right:0}
  #ipane-attend .kpi-row .kpi,#ipane-students .kpi-row .kpi{border-bottom:1px solid var(--border-soft)}
}

/* ---------- draft 10 layer (September 7 round 10): softer names, mono meta, sidebar hover, lists, previews ---------- */
.fh-app .att-row .item,.fh-app .roster-tbl tbody td:first-child,.fh-app .list .tc .item{font:500 14px/20px var(--font-body);color:var(--cab-blue-dark)}
.fh-app .att-row .im,.fh-app .num,.fh-app table.data td.num,.fh-app .roster-tbl td:nth-child(3){font-family:var(--font-mono);font-size:var(--type-meta);font-variant-numeric:tabular-nums;letter-spacing:0}
.fh-app .side-nav button[data-pane]:hover{background:var(--cab-blue);color:var(--cab-white);border-left-color:var(--cab-blue-dark)}
.fh-app .side-nav button[data-pane]:hover svg{stroke:var(--cab-white);opacity:1}
.fh-app .doc-list .tc{padding:12px 0}
/* FH-20260914 hotfix: .tc .r1 is space-between with no max-width, which is
   right for a narrow grid card but on a full-width document row pins the
   type kicker (PDF/Link/Excel) and the visibility pill to opposite edges,
   leaving a wide dead gap between two small, related tags (Gabe's screenshot
   annotation: "distracting... information is not being stacked"). Scoped to
   .doc-list only, so every other card's kicker-left/pill-right row (Forms,
   Announcements, Equipment) keeps the documented space-between pattern. */
/* FH-20260916: the row now reads title first (r2), then the type badge and
   visibility pill as one quiet line beneath it (r1), so the badge and pill
   no longer sit above the title with nothing but the more button in an
   otherwise empty row (Gabe's screenshot: "a heap on the left, an empty
   middle, one dot"). r1 keeps its flex-start grouping from the hotfix
   above; r2 now carries the space that used to sit under r1. */
.fh-app .doc-list .tc .r2{margin-bottom:4px}
.fh-app .doc-list .tc .r1{margin:0;justify-content:flex-start}
.fh-app .doc-list .r1 .kicker svg{width:16px;height:16px;margin-right:6px;stroke:currentColor;fill:none;stroke-width:1.75;vertical-align:-3px}
/* FH-20260914 hotfix: a topic sub-header inside General (grouped by the free-
   text documents.topic field) sat flush against the previous topic's last
   card, with less room above it than a normal card-to-card gap gets below it,
   so a new topic never registered as a new group (Gabe: "very small and hard
   to detect"). Extra margin-top on every topic kicker after the first makes
   each later topic break clearly; the first keeps its normal spacing under
   the phase-level "General" kicker above it. Scoped to .doc-list and to the
   General-only topic kickers (direct children of the list), so the shared
   .kicker type used everywhere else in the app, including the phase kicker
   itself, is untouched. */
.fh-app .doc-list>.kicker:not(:first-child){margin-top:28px}
.fh-app .notemark{width:14px;height:14px;stroke:var(--cab-ink-45);fill:none;stroke-width:1.75;vertical-align:-2px;margin-left:6px}
.fh-app .tc .preview{margin:4px 0 0;font:400 14px/20px var(--font-body);color:var(--cab-ink-80);max-width:var(--reading-max);display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.fh-app .hero--dark{margin-bottom:12px}
.fh-app .section-head .st{flex:none}

/* ---------- Projects, Progress grid and Timeline (draft 10, September 7 build) ----------
   The documentary team editor's cards, settings block and per-student note
   field no longer use <details>/<summary> (no expanders): a kicker replaces
   each summary, and the note field is always visible instead of toggled
   open. These restore the spacing the old >summary rules provided. Tokens
   only; everything else about the placement editor's layout is unchanged. */
.fold.placement-adjustments>.kicker{display:block;padding:14px 16px 0}
.placement-team-head{padding:13px 16px;border-bottom:1px solid var(--hairline)}
.placement-team-head .placement-count{float:right;margin-top:1px}
.placement-note-toggle{grid-column:1/-1;width:100%;padding:4px 0 2px}
.placement-note-toggle .im{display:block;margin:0 0 2px}
/* The progress grid matrix: a status symbol per cell, reusing the existing
   chip-static tones so the legend line and the panel breakdown agree. */
.fh-app table.data.grid td.num{padding:8px 6px;text-align:center}
.fh-app table.data.grid .chip-static{margin:0;padding:3px 8px;font-weight:700}
.fh-app .hero--dark{background:var(--cab-blue-dark);border-color:var(--cab-blue-dark)}

/* ---------- Course setup, Student work, Festival, Audience list and Exports (September 7 build) ----------
   The setting card's icon (DESIGN-SYSTEM.md section 4: icon in Primary Blue,
   bold title, one helper line, a chevron). Everything else on these five
   pages reuses .list, .tc, .cardgrid, .kpi-row and table.data as they stand. */
.fh-app .cardgrid .tc .setting-icon{display:inline-flex;flex:none;margin-right:12px}
.fh-app .cardgrid .tc .setting-icon svg{width:22px;height:22px;stroke:var(--cab-blue);fill:none;stroke-width:1.75;stroke-linecap:round;stroke-linejoin:round}
/* ---------- In-class groups, Pick a student, Calendar and Phases (September 7 draft 10 pages) ----------
   The Pick result card, the month grid and its legend. In-class groups and
   Phases reuse the existing list, tapCard, ctx, qf, tbl-wrap and panel
   primitives above and add no rules of their own. Tokens only. */
.pick-result{max-width:420px;text-align:center;padding:32px 24px}
.pick-result .pick-name{margin:0;font:500 22px/28px var(--font-body);color:var(--cab-blue-dark)}
.pick-result .im{justify-content:center;text-align:center}
.cal-grid{display:grid;grid-template-columns:repeat(7,minmax(0,1fr));gap:1px;background:var(--border-soft);border:1px solid var(--hairline);margin:0 0 12px}
.cal-dow{background:var(--surface);padding:8px;font:600 10px/16px var(--font-body);letter-spacing:.1em;text-transform:uppercase;color:var(--cab-ink-50);text-align:center}
.cal-cell{background:var(--surface);min-height:84px;padding:8px;cursor:pointer;transition:background-color var(--dur-fast) var(--ease-standard)}
.cal-cell:hover{background:var(--surface-hover)}
.cal-cell:focus-visible{outline:2px solid var(--cab-blue-dark);outline-offset:-2px}
.cal-cell--pad{cursor:default;background:var(--surface-tint)}
.cal-cell--today{box-shadow:inset 0 0 0 2px var(--cab-blue)}
.cal-daynum{font:600 12px/16px var(--font-mono);color:var(--ink)}
.cal-dot{display:flex;align-items:center;gap:6px;margin-top:6px;font:400 12px/16px var(--font-body);color:var(--ink);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.cal-dot::before{content:"";width:7px;height:7px;border-radius:50%;background:var(--cab-blue);flex:none}
.cal-dot--off::before{background:var(--warn)}
.cal-dot--shoot::before{background:var(--cab-orange)}
.cal-dot--mine{font-weight:600}
.cal-legend span.mine::before{background:var(--cab-orange);box-shadow:0 0 0 2px var(--surface),0 0 0 3px var(--cab-orange)}
.cal-dot--mine::before{box-shadow:0 0 0 2px var(--surface),0 0 0 3px var(--cab-orange)}
.cal-dot--more{color:var(--muted)}
.cal-legend{display:flex;flex-wrap:wrap;gap:6px 16px}
.cal-legend span{display:inline-flex;align-items:center;gap:6px}
.cal-legend span::before{content:"";width:7px;height:7px;border-radius:50%;background:var(--cab-blue)}
.cal-legend span.shoot::before{background:var(--cab-orange)}
.date-row input[type="time"]{width:auto;min-width:0}
.cal-legend span.off::before{background:var(--warn)}
@media (max-width:720px){
  .cal-grid{grid-template-columns:repeat(7,minmax(0,1fr))}
  .cal-cell{min-height:56px;padding:4px}
  .cal-dot{font-size:10px}
}

/* Portal minimalism: deliberately scoped; public Cabrillo pages are unchanged. */
.fh-app.fh-portal :is(.btn,.qf__b,.chips button,.st,.chip-static,.fold__pill,.fold__count){border-radius:var(--portal-control-radius)}
.fh-app.fh-portal :is(.btn,.qf__b,.chips button){min-height:var(--portal-control-height)}
.fh-app.fh-portal .panel__head{padding:var(--portal-panel-pad) var(--portal-panel-pad) var(--portal-space)}
.fh-app.fh-portal .panel__body{padding:0 var(--portal-panel-pad) var(--portal-panel-pad)}
.fh-app.fh-portal .panel__actions{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,var(--portal-action-min)),1fr));gap:var(--portal-space);padding:var(--portal-space) var(--portal-panel-pad) var(--portal-panel-pad)}
.fh-app.fh-portal .panel__actions[hidden]{display:none}
.fh-app.fh-portal .panel__actions .btn{min-width:0;white-space:normal;overflow-wrap:anywhere}
.fh-app.fh-portal .panel__actions > :is([role=status],[role=alert]){grid-column:1/-1;min-width:0;white-space:normal;overflow-wrap:anywhere}
.fh-app.fh-portal #staff-filter{display:block;width:100%;min-width:0;min-height:var(--portal-control-height);margin-top:var(--portal-space);padding:var(--portal-control-pad);font:400 1rem/1.4 var(--font-body);color:var(--ink);background:var(--surface);border:1px solid var(--hairline);border-radius:var(--portal-control-radius)}
.fh-app.fh-portal #staff-content>.tbl-wrap:has(#staff-rows){max-width:100%;overflow-x:auto}
.fh-app.fh-portal #staff-content>.tbl-wrap:has(#staff-rows)>table{min-width:calc(4 * var(--portal-field-min));table-layout:fixed}
.fh-app.fh-portal #staff-rows td{overflow-wrap:anywhere}
.fh-app.fh-portal #staff-rows [data-record]{max-width:100%;white-space:normal;overflow-wrap:anywhere;text-align:start}
.fh-app.fh-portal #home-sheet svg{width:var(--space-6);height:var(--space-6);flex:none;stroke:currentColor;fill:none;stroke-width:1.75;stroke-linecap:round;stroke-linejoin:round}
.fh-app.fh-portal #home-sheet button{min-width:0;flex:none}
.fh-app.fh-portal #home-sheet button span{min-width:0;overflow-wrap:anywhere}
.fh-app.fh-portal .portal-text-action{background:transparent;border:0;border-radius:var(--portal-control-radius);color:var(--text-link);font:inherit;font-size:var(--type-support);padding:var(--portal-control-pad);min-height:var(--portal-control-height);cursor:pointer;text-align:start;white-space:normal}
.fh-app.fh-portal .portal-text-action:hover{text-decoration:underline;background:var(--surface-muted)}
.fh-app.fh-portal .portal-text-action:focus-visible{outline:2px solid var(--text-link);outline-offset:2px}
.fh-app.fh-portal .studio-preparation-actions{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--portal-space);margin-block:var(--portal-space) var(--portal-space-large)}
.fh-app.fh-portal .studio-review-actions{grid-column:1/-1;display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);align-items:center;gap:var(--portal-space)}
.fh-app.fh-portal .studio-review-back{justify-self:end;text-align:end}
.fh-app.fh-portal .studio-review-actions>.btn{justify-self:start}
.fh-app.fh-portal .studio-requirements .tc .r2{display:grid;grid-template-columns:minmax(0,1fr) auto}
.fh-app.fh-portal .studio-requirements .tc .r2 .item{grid-column:1/-1}
.fh-app.fh-portal .studio-requirements .tc .r2 .st{justify-self:start;max-width:100%;white-space:normal;overflow-wrap:anywhere}
.fh-app.fh-portal .equipment-more-actions{position:relative}
.fh-app.fh-portal .equipment-more-actions>summary{cursor:pointer;padding:var(--portal-control-pad);min-height:var(--portal-control-height);font-size:var(--type-support)}
.fh-app.fh-portal .equipment-more-actions__menu{position:absolute;right:0;top:100%;z-index:10;display:grid;min-width:var(--portal-action-min);background:var(--surface);border:1px solid var(--hairline);box-shadow:var(--shadow-raised);padding:var(--portal-space)}
/* A panel footer is one row that never wraps into a stack of boxed
   actions: at most one primary button plus the shared More actions
   details/summary menu (Gabe, 19 Sep 2026, on the Projects production
   panel). #panel-actions is a shared single-instance container across
   every panel in the app, so this row is its own scoped child instead of
   a change to #panel-actions itself. */
.fh-app.fh-portal .panel-actions-row{display:flex;flex-wrap:nowrap;align-items:center;gap:var(--portal-space);min-width:0}
.fh-app.fh-portal .panel-actions-row>.btn{flex:none;white-space:nowrap}
.fh-app.fh-portal .panel-actions-row>.equipment-more-actions{flex:none}
.fh-app.fh-portal .overview-fold{margin-block:0 var(--portal-space-large)}
.fh-app.fh-portal .overview-fold>summary{display:flex;align-items:center;gap:var(--portal-space);padding:var(--space-2) 0;text-transform:none;letter-spacing:0;color:var(--cab-blue-dark)}
.fh-app.fh-portal .overview-fold>summary::after{margin-left:auto}
.fh-app.fh-portal .overview-fold__heading{font-size:var(--type-section-heading);line-height:1.5;font-weight:600}
.fh-app.fh-portal .overview-fold>.fold__body{padding:var(--portal-space) 0 0}
.fh-app.fh-portal .equipment-request-grid{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--portal-space)}
.fh-app.fh-portal .equipment-request-card{margin:0;min-width:0}
.fh-app.fh-portal .equipment-request-card__head{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--portal-space);min-width:0}
.fh-app.fh-portal .equipment-request-card__head>.st{flex:none;white-space:nowrap}
.fh-app.fh-portal .equipment-request-select{display:flex;align-items:flex-start;gap:var(--portal-space);min-width:0;max-width:100%;flex:1 1 auto;margin:0;font-weight:400;cursor:pointer}
.fh-app.fh-portal .equipment-request-select>input{flex:none}
.fh-app.fh-portal .equipment-request-select>span{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--space-1);min-width:0;max-width:100%;width:100%;flex:1 1 auto}
.fh-app.fh-portal .equipment-request-select strong{display:block;min-width:0;max-width:100%;width:100%;white-space:normal;overflow-wrap:anywhere;word-break:break-word}
.fh-app.fh-portal .equipment-request-card>.r2{min-width:0}
.fh-app.fh-portal .equipment-request-card>.r2>.item{min-width:0;overflow-wrap:anywhere}
.fh-app.fh-portal .equipment-request-card>.r2>.st{flex:none;white-space:nowrap}
.fh-app.fh-portal .equipment-request-lines{margin-top:var(--portal-space);border-top:1px solid var(--hairline)}
.fh-app.fh-portal .equipment-request-line{padding:var(--portal-space) 0;border-bottom:1px solid var(--hairline)}
.fh-app.fh-portal .equipment-request-line>label{display:flex;align-items:flex-start;gap:var(--portal-space);margin:0;font-weight:400;cursor:pointer}
.fh-app.fh-portal .equipment-request-child{margin:var(--space-1) 0 0 calc(var(--portal-control-height) + var(--portal-space));color:var(--muted);font-size:var(--type-caption)}
.fh-app.fh-portal .equipment-request-card__quiet{margin-top:var(--portal-space)}
.fh-app.fh-portal .equipment-return-tools{max-width:68ch;margin:0 0 var(--portal-space-large)}
.fh-app.fh-portal .equipment-return-tools input{width:100%;margin-bottom:var(--portal-space)}
.fh-app.fh-portal .equipment-return-tools .panel-actions-row{justify-content:flex-start}
/* Live regression found reviewing Skate Ramsay's Greenlight review footer:
   .panel is position:fixed with bottom:0, so .panel__actions (its last flex
   child) always sits at the very bottom edge of the viewport. The shared
   dropdown's default top:100% opens the menu downward, which pushed its
   three buttons below the visible viewport on every panel footer, on any
   screen where the panel body did not happen to leave enough room below;
   the sliver of the menu that stayed on screen at the trigger's own edge
   read as an empty box, with no styling defect (contrast and content were
   correct once scrolled into view). Opening upward keeps a panel footer's
   own More actions menu on screen regardless of viewport height. */
.fh-app.fh-portal .panel-actions-row .equipment-more-actions__menu{top:auto;bottom:100%;margin-bottom:4px}
.fh-app.fh-portal .equipment-workspace>.subtabs{display:grid;grid-template-columns:repeat(4,minmax(0,1fr))}
.fh-app.fh-portal .equipment-workspace>.subtabs .subtab{min-width:0;white-space:normal;padding:var(--portal-control-pad);min-height:var(--portal-control-height)}
.fh-app.fh-portal .equipment-section-picker,.fh-app.fh-portal .equipment-category-picker{display:none}
/* Announcement filters use intentional rows, not a wrapping action cluster. */
.fh-app.fh-portal #ipane-opps .announcement-filters{display:grid;gap:var(--portal-space);margin-block:var(--portal-space) var(--portal-space-large)}
.fh-app.fh-portal #ipane-opps .announcement-filter-state{min-width:0}
.fh-app.fh-portal #ipane-opps .announcement-filter-state>.qf{flex-wrap:nowrap;margin:0}
.fh-app.fh-portal #ipane-opps .announcement-filter-fields{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--portal-space)}
.fh-app.fh-portal #ipane-opps .announcement-filter-fields>.grow{min-width:0}
.fh-app.fh-portal #ipane-opps .announcement-filters label{display:block;margin:0 0 var(--portal-space)}
.fh-app.fh-portal #ipane-opps .announcement-filters select{width:100%;min-width:0;max-width:none;min-height:var(--portal-control-height)}
.fh-app.fh-portal #ipane-opps .announcement-state-picker{display:none}
@media(max-width:720px){
  .fh-app.fh-portal #ipane-opps .announcement-filter-state>.qf{display:none}
  .fh-app.fh-portal #ipane-opps .announcement-state-picker{display:block}
  .fh-app.fh-portal #ipane-opps .announcement-filter-fields{grid-template-columns:minmax(0,1fr)}
}
.fh-app.fh-portal .production-section-picker{display:none}
.fh-app.fh-portal .production-section-picker select{width:100%;min-width:0;min-height:var(--portal-control-height)}
.fh-app.fh-portal .student-overview-status{margin-bottom:var(--portal-space-large);min-width:0}
.fh-app.fh-portal .student-overview-status .clear-band{margin-bottom:var(--portal-space)}
.fh-app.fh-portal .student-overview-next{display:flex;flex-wrap:nowrap;align-items:flex-start;justify-content:space-between;gap:var(--portal-space-large);padding:var(--card-pad);background:var(--surface);border:1px solid var(--border-soft);min-width:0}
.fh-app.fh-portal .student-overview-next>div{min-width:0;max-width:68ch}
.fh-app.fh-portal .student-overview-next h2,.fh-app.fh-portal .student-overview-card h2{margin:0 0 var(--space-1);font-size:var(--type-section-heading);line-height:1.5;color:var(--cab-blue-dark)}
.fh-app.fh-portal .student-overview-next p{margin:0;line-height:1.55}
.fh-app.fh-portal .student-overview-next>.btn{flex:none;white-space:nowrap}
.fh-app.fh-portal .student-overview-status>#studio-status{max-width:68ch;margin-top:var(--space-1)}
.fh-app.fh-portal .student-overview-grid{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--portal-space-large);align-items:start;min-width:0}
.fh-app.fh-portal .student-overview-card{min-width:0;margin:0;padding:var(--card-pad)}
.fh-app.fh-portal .student-overview-card p{max-width:68ch}
.fh-app.fh-portal .student-overview-metric{margin:0 0 var(--space-1);line-height:1.5}
.fh-app.fh-portal .student-overview-metric strong{font-size:var(--type-section-heading);color:var(--cab-blue-dark)}
.fh-app.fh-portal .student-overview-actions{display:flex;flex-wrap:nowrap;gap:var(--portal-space);margin-top:var(--portal-space)}
.fh-app.fh-portal .student-overview-actions>.btn{flex:none;white-space:nowrap}
.fh-app.fh-portal .student-overview-fold{margin:var(--portal-space) 0 0}
.fh-app.fh-portal .student-overview-fold>summary{min-height:var(--portal-control-height)}
.fh-app.fh-portal .student-overview-note{border-left:4px solid var(--cab-gold);padding-left:var(--portal-space);margin-top:var(--portal-space)}
.fh-app.fh-portal .student-overview-note p{margin:0;white-space:pre-wrap}
.fh-app.fh-portal .student-overview-note p+p{margin-top:var(--space-1)}
.fh-app.fh-portal .student-overview-crew{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--space-1) var(--portal-space);margin-top:var(--portal-space)}
.fh-app.fh-portal .student-overview-crew p{margin:0;min-width:0}
.fh-app.fh-portal .student-overview-crew strong,.fh-app.fh-portal .student-overview-crew span{display:block;min-width:0;overflow-wrap:anywhere}
.fh-app.fh-portal .student-overview-due{display:flex;flex-wrap:nowrap;align-items:flex-start;justify-content:space-between;gap:var(--portal-space);min-width:0}
.fh-app.fh-portal .student-overview-due>div{min-width:0}
.fh-app.fh-portal .student-overview-due>.btn{flex:none;white-space:nowrap}
@media(min-width:768px){
  .fh-app.fh-portal .student-overview-grid{grid-template-columns:repeat(2,minmax(0,1fr))}
  .fh-app.fh-portal .student-overview-crew{grid-template-columns:repeat(2,minmax(0,1fr))}
}
@media(max-width:720px){
  .fh-app.fh-portal .student-overview-next{flex-direction:column;align-items:flex-start;padding:var(--card-pad-phone)}
  .fh-app.fh-portal .student-overview-next>.btn,.fh-app.fh-portal .student-overview-actions>.btn,.fh-app.fh-portal .student-overview-due>.btn{min-height:var(--control-height-phone)}
  .fh-app.fh-portal .student-overview-card{padding:var(--card-pad-phone)}
  .fh-app.fh-portal .student-overview-fold>summary{min-height:var(--control-height-phone)}
}
.fh-app.fh-portal :is(.equipment-section-picker,.equipment-category-picker) select{min-height:var(--portal-control-height);width:100%}
/* Student record panel (Inst.renderStudentRecord): the section picker here
   is unconditional, at every width, rather than swapping in only under the
   phone breakpoint the way Equipment and the production panel do above.
   .panel is a fixed 520px slide over (width:520px above) no matter how wide
   the browser window is, so "desktop" never actually gives this panel more
   room the way it gives the full-width Equipment and production pages more
   room; five tab labels (Notes, Attendance, Assignments, Equipment,
   Activity) squeezed into that fixed width would still wrap or crowd at
   1440 exactly as they would at 320. The select stays clean and nowrap at
   every measured width instead. */
.fh-app.fh-portal .rec-workspace>.subtabs{display:none}
.fh-app.fh-portal .rec-section-picker{display:block;margin-bottom:var(--portal-space)}
.fh-app.fh-portal .rec-section-picker select{width:100%;min-width:0;min-height:var(--portal-control-height)}
.fh-app.fh-portal .equipment-filters{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--portal-space);margin-bottom:var(--portal-space-large)}
.fh-app.fh-portal .equipment-filter-search{width:100%;min-width:0;max-width:none;margin:0}
.fh-app.fh-portal .equipment-filter-search input{width:100%;min-width:0;max-width:none;margin:0;min-height:var(--portal-control-height)}
.fh-app.fh-portal .equipment-filter-category .qf{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,var(--portal-field-min)),1fr));margin:0;gap:var(--portal-space)}
.fh-app.fh-portal .equipment-filter-category .qf__b{border:0;background:transparent;color:var(--ink);border-radius:0;border-bottom:2px solid transparent}
.fh-app.fh-portal .equipment-filter-category .qf__b[aria-pressed=true]{border-bottom-color:var(--action);color:var(--action);font-weight:600}
.fh-app.fh-portal .equipment-filter-fields{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:var(--portal-space)}
.fh-app.fh-portal .equipment-filter-field{min-width:0}
.fh-app.fh-portal .equipment-filter-field label{display:block;margin:0 0 var(--portal-space)}
.fh-app.fh-portal .equipment-filter-fields .qf__sel{width:100%;min-width:0;max-width:none;min-height:var(--portal-control-height)}
.fh-app.fh-portal .eq-grid>.tc{min-width:0}
.fh-app.fh-portal .eq-grid>.tc .r1{display:grid;grid-template-columns:minmax(0,1fr);justify-items:start;gap:var(--space-1)}
.fh-app.fh-portal .eq-grid>.tc .r1 .st{max-width:100%;white-space:normal;overflow-wrap:anywhere}
@media(max-width:1024px){
  .fh-app.fh-portal .equipment-filter-fields{grid-template-columns:repeat(2,minmax(0,1fr))}
  .fh-app.fh-portal .eq-grid{grid-template-columns:repeat(2,minmax(0,1fr))}
}
@media(min-width:721px) and (max-width:1024px){
  .fh-app.fh-portal .checkout-loans{min-width:calc(6 * var(--portal-field-min))}
}
@media(max-width:720px){
  .fh-app.fh-portal .checkout-loans thead{display:none}
  .fh-app.fh-portal .checkout-loans,.fh-app.fh-portal .checkout-loans tbody{display:block;width:100%}
  .fh-app.fh-portal .checkout-loans tr.grp-row{display:block;padding:var(--portal-space) 0}
  .fh-app.fh-portal .checkout-loans tr.grp-row td{display:block;padding:0;border:0;overflow-wrap:anywhere}
  .fh-app.fh-portal .checkout-loans tr:not(.grp-row){display:grid;grid-template-columns:minmax(0,1fr) auto;column-gap:var(--portal-space);align-items:start;border-bottom:1px solid var(--border-soft);padding:var(--portal-space) 0}
  .fh-app.fh-portal .checkout-loans tr:not(.grp-row)>td{display:block;grid-column:1;min-width:0;padding:var(--space-1) 0;border:0;white-space:normal;overflow-wrap:anywhere;text-align:start}
  .fh-app.fh-portal .checkout-loans td[data-label]::before{content:attr(data-label);display:block;font:600 .78rem/1.5 var(--font-body);color:var(--muted)}
  .fh-app.fh-portal .checkout-loans tr:not(.grp-row)>td.cv-cell{grid-column:2;grid-row:1;width:auto;padding:0}
}
/* An unbroken token (a guest's email address, a long name with no spaces)
   still forces an auto-layout table wider than its container above the
   720 px breakpoint below, where the table has not yet switched to the
   stacked-card layout; found measuring the Releases table at 768 and
   1440 CSS px, right after the phone-width fix below looked complete
   (the hard rule on actions, Gabe, 19 Sep 2026: every width, not just
   phone). Applies regardless of width so nothing here ever depends on
   catching every breakpoint. */
.fh-app.fh-portal .crew-table td,.fh-app.fh-portal .rel-table td{overflow-wrap:anywhere}
/* overflow-wrap:anywhere alone is not enough above 720 px: an auto-layout
   table's own minimum content width, used to decide whether the table may
   exceed its 100% width, is computed from line-break opportunities
   (spaces), not from character-level overflow-wrap breaks, so an
   unbroken guest email still grew the whole table past its container
   even with wrapping enabled on the cell. table-layout:fixed removes
   content from that decision entirely: columns split the table's own
   (already-bounded) width, and cell text wraps inside whatever share
   they get, every time. */
.fh-app.fh-portal .crew-table,.fh-app.fh-portal .rel-table{table-layout:fixed}
/* table-layout:fixed narrows the action column along with every other one;
   two buttons that used to sit on one unbreakable line (the base
   .rel-table td:last-child rule) no longer both fit there, so they wrap
   onto their own lines within that column instead of pushing past it. */
.fh-app.fh-portal .rel-table td:last-child{white-space:normal}
.fh-app.fh-portal .rel-table td:last-child .btn{margin:0 8px 8px 0}
/* Crew header (the production panel's Volunteer Agreement caption plus the
   quiet Nudge everyone unsigned button): a caption that wraps freely and a
   button that never shrinks below its own label or the 44 px target, on
   one row, neither ever pushing the panel wider than its own edge (the
   hard rule on actions, Gabe, 19 Sep 2026). */
.fh-app.fh-portal .crew-agreement-row{display:flex;flex-wrap:wrap;align-items:center;gap:var(--portal-space);margin:0 0 10px}
.fh-app.fh-portal .crew-agreement-row>p{margin:0;min-width:0;flex:1 1 auto;overflow-wrap:anywhere}
.fh-app.fh-portal .crew-agreement-row>.btn{flex:none}
/* The crew table (crewTable(), portal-shared.php): at 320/375 CSS px, Name,
   Role and Volunteer Agreement in fixed columns cannot fit a phone width
   without either clipping or forcing the whole panel wider (found
   measuring the production panel: panel__body's missing min-width:0 let a
   wide crew-table stretch the panel past the viewport with no scrollbar
   and no page-level overflow signal). Below 720 px each row becomes one
   labeled block instead, the same pattern .checkout-loans already uses. */
@media(max-width:720px){
  .fh-app.fh-portal .crew-table thead{display:none}
  .fh-app.fh-portal .crew-table,.fh-app.fh-portal .crew-table tbody{display:block;width:100%}
  .fh-app.fh-portal .crew-table tr{display:block;border-bottom:1px solid var(--border-soft);padding:var(--portal-space) 0}
  .fh-app.fh-portal .crew-table tr:last-child{border-bottom:0}
  .fh-app.fh-portal .crew-table td{display:block;min-width:0;padding:var(--space-1) 0;border:0;white-space:normal;overflow-wrap:anywhere;text-align:start!important}
  .fh-app.fh-portal .crew-table td[data-label]::before{content:attr(data-label);display:block;font:600 .78rem/1.5 var(--font-body);color:var(--muted)}
}
/* The Releases and agreements table (Rel.render, portal-shared.php): same
   reasoning and same pattern as .crew-table above. A long guest name or
   email in the Signer cell was the exact overflow measured in the
   instructor production panel at 375 CSS px. */
@media(max-width:720px){
  .fh-app.fh-portal .rel-table thead{display:none}
  .fh-app.fh-portal .rel-table,.fh-app.fh-portal .rel-table tbody{display:block;width:100%}
  .fh-app.fh-portal .rel-table tr{display:block;border-bottom:1px solid var(--border-soft);padding:var(--portal-space) 0}
  .fh-app.fh-portal .rel-table tr:last-child{border-bottom:0}
  .fh-app.fh-portal .rel-table td{display:block;min-width:0;padding:var(--space-1) 0;border:0;white-space:normal;overflow-wrap:anywhere;text-align:start!important}
  .fh-app.fh-portal .rel-table td[data-label]::before{content:attr(data-label);display:block;font:600 .78rem/1.5 var(--font-body);color:var(--muted)}
}
@media(max-width:720px){
  .fh-app.fh-portal{--portal-control-height:var(--control-height-phone);--portal-panel-pad:var(--card-pad-phone)}
  .fh-app.fh-portal .eq-grid{grid-template-columns:minmax(0,1fr)}
  .fh-app.fh-portal #inst-main .btn-small,.fh-app.fh-portal .eq-unit-actions .btn{min-height:var(--control-height-phone)}
  .fh-app.fh-portal .equipment-workspace>.subtabs,.fh-app.fh-portal .equipment-filter-category .qf{display:none}
  .fh-app.fh-portal .equipment-section-picker,.fh-app.fh-portal .equipment-category-picker{display:block;margin-bottom:var(--portal-space)}
  .fh-app.fh-portal #prod-tabs{display:none}
  .fh-app.fh-portal .production-section-picker{display:block;margin-block:var(--portal-space) var(--portal-space-large)}
}
/* CERT-083: close the remaining phone tap-target gaps inside the portal scope.
   The portal scope sets its own control heights after the earlier phone rule,
   so fields, the account menu and the panel close kept desktop heights.
   Measured at 375 CSS px before this: account menu items 40, panel close 32,
   text fields 36 and selects 34. Heights only; no layout is rebuilt here. */
@media (max-width: 720px) {
  .fh-app.fh-portal .btn-small {
    min-width: var(--control-height-phone);
    min-height: var(--control-height-phone);
  }
  .fh-app.fh-portal #preview-banner .btn.btn-small {
    min-width: var(--control-height-phone);
    min-height: var(--control-height-phone);
  }
  /* Production page controls that do not use the shared button or field
     classes still need the same phone target height. The negative margin on
     the back link preserves its existing line in the page flow while its tap
     box grows around the text. */
  .fh-app.fh-portal .back-link {
    display: inline-flex;
    align-items: center;
    min-height: var(--control-height-phone);
    margin-block: -12px;
  }
  .fh-app.fh-portal #prod-pane-releases .fold > summary,
  .fh-app.fh-portal .student-equip-includes > summary,
  .fh-app.fh-portal .doc-embed a,
  .fh-app.fh-portal .fbody .card a {
    display: inline-flex;
    align-items: center;
    min-height: var(--control-height-phone);
  }
  .fh-app.fh-portal #hi-file input[type=file] {
    min-height: var(--control-height-phone);
    font-size: 1rem;
  }
  .fh-app .acct__item,
  .fh-app .panel__close,
  .test-lane-toggle,
  .fh-app .qf .qf__search,
  .fh-app .keyrow .qf__search,
  .qf .qf__search,
  .keyrow .qf__search,
  .tc .more,
  .att-more,
  .prep-item-action,
  .acct summary,
  .th-sort,
  .fh-app :is(input[type=text],input[type=email],input[type=password],input[type=tel],input[type=date],input[type=time],input[type=number],input[type=url],input[type=search],select,textarea) { min-height: var(--control-height-phone); }
  .tc .more,
  .att-more,
  .acct summary,
  .fh-app .panel__close { min-width: var(--control-height-phone); }
  .fh-app.fh-portal .overview-fold>summary,
  .fh-app.fh-portal .equipment-request-select,
  .fh-app.fh-portal .equipment-request-line>label { min-height:var(--control-height-phone); }
  /* .th-sort is a bare <button> with no flex layout, so raising min-height
     alone would leave its label pinned to the top of the new taller box on
     phones instead of centered against the header row. */
  .th-sort { display: inline-flex; align-items: center; }
  /* Checkbox tap targets (finding 4): enlarge the associated <label>, never
     the 20px checkbox itself. Two label shapes exist in this codebase: the
     checkbox nested inside its own <label> (.prep-item-check, the term-day
     picker, the studio setup checkboxes), and the .radio-row shape where the
     checkbox and its <label for="..."> are siblings. .cb-tap covers the one
     remaining case with no label at all (the Phases document picker). */
  label:has(> input[type=checkbox]),
  .radio-row label,
  .cb-tap { min-height: var(--control-height-phone); }
  .radio-row label { display: inline-flex; align-items: center; }
  .cb-tap { min-width: var(--control-height-phone); }
  /* iOS Safari zooms the page on focus whenever a field's computed font size
     is under 16px. .fh-app :is(input[type=...],select){font:...13px...} at
     line 1317 (unconditional, higher specificity than typography.css's own
     phone rule) was winning over every attempt to bring fields back to 16px
     on a phone, and several instructor-only field rules with no type
     attribute (so line 1317 never matched them) were never touched at all.
     One rule here, at the same breakpoint as the tap-target fix above, is
     the single place left that can out-specify all of them at once. Sizes
     only; no layout changes here. */
  .fh-app :is(input[type=text],input[type=email],input[type=password],input[type=tel],input[type=date],input[type=time],input[type=number],input[type=url],input[type=search],select,textarea),
  .prep-item-edit input,
  .placement-settings__field select,
  .placement-settings__field input,
  .placement-swap select,
  .placement-team-name input,
  .placement-control select,
  .placement-note-toggle input,
  .qf__sel {
    font-size: 1rem;
  }
  /* A status chip carrying a whole sentence is flex:none above, so on a phone it
     ran past the page edge instead of using the width it had. Let the row wrap
     and let the chip take the line and wrap its own text. */
  .fh-app .section-head { flex-wrap: wrap; }
  .fh-app .section-head .st { flex: 1 1 auto; min-width: 0; white-space: normal; }
}
