/* =================== Lab portal styles (generated) ==================
   GENERATED by scripts/build_portal.py. Edit PORTAL_CSS there and re-run;
   changes made here are overwritten.

   These live in their own file, not in style.css, on purpose. style.css is
   edited by hand while the portal is being generated, and appending to it
   meant a hand save and a build could race and one would lose the other.
   Nothing here overrides a public-page rule: the portal reuses .page-head,
   .block, .sec-head and the type scale, and only adds new selectors. Loaded
   after style.css, and only by portal pages. */

/* Gate. <html> carries .portal-locked until it clears, so the page never
   paints its contents behind the overlay. */
html.portal-locked body > *:not(.portal-gate) { display: none !important; }
.portal-gate {
  position: fixed; inset: 0; z-index: 200;
  display: flex; align-items: center; justify-content: center;
  background: var(--navy-950); padding: var(--gutter);
}
.portal-gate-panel { width: 100%; max-width: 420px; text-align: center; }
.portal-gate-mark { height: 40px; width: auto; margin: 0 auto 34px; }
.portal-gate h1 {
  font-family: var(--font-display); font-weight: var(--fw-light);
  font-size: var(--fs-5); letter-spacing: var(--tr-snug); color: #fff; margin: 0 0 10px;
}
.portal-gate p { color: #9fb3d2; font-size: var(--fs-0); margin: 0 0 30px; line-height: 1.7; }
.portal-gate input {
  width: 100%; padding: 13px 2px; margin: 0 0 20px;
  background: transparent; color: #fff;
  border: 0; border-bottom: 1px solid rgba(255,255,255,.28);
  font-family: var(--font-body); font-size: var(--fs-1);
  text-align: center; letter-spacing: .04em;
  transition: border-color .25s var(--ease);
}
.portal-gate input:focus { outline: 0; border-bottom-color: var(--blue-light); }
.portal-gate button {
  width: 100%; padding: 14px 20px; border: 0; cursor: pointer;
  background: var(--blue); color: #fff;
  font-family: var(--font-body); font-size: var(--fs--2); font-weight: var(--fw-semi);
  letter-spacing: var(--tr-caps); text-transform: uppercase;
  transition: background .25s var(--ease);
}
.portal-gate button:hover { background: var(--blue-light); color: var(--navy); }
.portal-gate .gate-error {
  min-height: 20px; margin: 16px 0 0; font-size: var(--fs--1); color: #e88;
  opacity: 0; transition: opacity .2s var(--ease);
}
.portal-gate .gate-error.show { opacity: 1; }
.portal-gate .gate-foot { margin: 30px 0 0; font-size: var(--fs--2); color: #6d7f9c; }
.portal-gate .gate-foot a { color: #8ea6c9; }

/* Compact page header. The public .page-head is a hero: 104px/88px of padding
   and a 60px title, which is right for a landing page and absurd on a utility
   page you are passing through to reach a form. About a third the height. */
.page-head.portal { padding: 38px 0 32px; }
.page-head.portal h1 { font-size: clamp(24px, 2.6vw, 32px); letter-spacing: var(--tr-snug); }
.page-head.portal p { margin: 9px 0 0; font-size: var(--fs-0); max-width: 640px; line-height: 1.65; }
/* the band below a portal header does not need the full 92px lead-in either */
.page-head.portal + section.block { padding-top: var(--band-sm); }

/* Sticky stack on a synced-document page (handbook, safety, documentation).
   style.css sticks .hb-bar at 76px, which is where the PORTAL BAR already
   sits, at a higher z-index, so on every internal page the document bar slid
   underneath it and vanished the moment you scrolled: the page title and the
   Contents and Collapse buttons were only visible at the very top. Stack them
   instead. The offsets come from --chrome-top / --chrome-full, measured by
   stickyChrome() in site.js because the bars are 76/54 wide-screen and 66/48
   below the breakpoints; the fallbacks are the wide-screen values, so the
   layout is right even before the script runs. */
.hb-bar { top: var(--chrome-top, 130px); z-index: 30; }
.hb-toc { top: calc(var(--chrome-full, 180px) + 12px); }
.hb-content h2, .hb-content h3, .sf-doc h2, .sf-doc h3 {
  scroll-margin-top: calc(var(--chrome-full, 180px) + 14px);
}

/* Internal badge, so a portal page is never mistaken for a public one */
.portal-badge {
  display: inline-block; margin: 0 0 10px; padding: 4px 10px;
  background: rgba(127,178,229,.16); border: 1px solid rgba(127,178,229,.34);
  color: var(--blue-light);
  font-size: var(--fs-micro); font-weight: var(--fw-semi);
  letter-spacing: var(--tr-caps); text-transform: uppercase;
}

/* Portal section bar, pinned under the sticky 76px header so the portal stays
   navigable from anywhere on a long page. Solid background or pinned content
   shows through. Scrolls sideways rather than wrapping to two rows. */
/* Second-level strip. Grouped into hover menus so all thirty portal
   destinations are two clicks away from anywhere, not just the eleven that
   used to fit on one line. Class names are shared with the main nav
   (.dropdown / .dd-toggle / .dropdown-menu) so site.js's existing
   tap-to-open and click-outside-to-close apply with no new javascript.
   overflow must stay visible here: the old overflow-x:auto would clip an
   absolutely positioned menu, which is why the bar collapses to one button
   on small screens instead of scrolling sideways. */
.portal-bar {
  position: sticky; top: 76px; z-index: 40;
  background: var(--bg-soft-2); border-bottom: 1px solid var(--line);
}
.portal-bar .wrap {
  display: flex; flex-wrap: nowrap; align-items: center; gap: 8px 20px;
  padding-top: 9px; padding-bottom: 9px;
  overflow: visible;
}
.portal-bar .pb-items {
  display: flex; flex-wrap: nowrap; align-items: center; gap: 4px 4px;
  min-width: 0;
}
.portal-bar a, .portal-bar .pb-toggle {
  white-space: nowrap;
  font-family: var(--font-body);
  font-size: var(--fs--2); letter-spacing: .06em; text-transform: uppercase;
  color: var(--muted); font-weight: var(--fw-med);
  transition: color .2s var(--ease), background .2s var(--ease);
}
.portal-bar .pb-items > a,
.portal-bar .pb-toggle {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 7px 11px; border: 0; border-radius: 3px;
  background: none; cursor: pointer;
}
.portal-bar .pb-items > a:hover,
.portal-bar .pb-toggle:hover,
.portal-bar .pb-group:hover .pb-toggle {
  color: var(--navy); background: rgba(20,44,79,.07); text-decoration: none;
}
.portal-bar .pb-items > a.here,
.portal-bar .pb-group.has-here .pb-toggle {
  color: var(--navy); background: rgba(20,44,79,.09);
  box-shadow: inset 0 -2px 0 var(--blue);
}
.portal-bar .pb-toggle .chev {
  font-size: 9px; transition: transform .25s var(--ease);
}
.portal-bar .pb-group:hover .pb-toggle .chev,
.portal-bar .pb-group.open .pb-toggle .chev { transform: rotate(180deg); }

.portal-bar .pb-group { position: relative; display: inline-flex; align-items: center; }
.portal-bar .pb-menu {
  position: absolute; top: 100%; left: 0; min-width: 232px; padding: 8px;
  background: #fff; border: 1px solid var(--line); border-top: 2px solid var(--blue);
  box-shadow: 0 14px 34px rgba(9,16,36,.14);
  opacity: 0; visibility: hidden; transform: translateY(6px);
  transition: opacity .2s var(--ease), transform .2s var(--ease), visibility .2s;
  z-index: 60;
}
.portal-bar .pb-group:hover .pb-menu,
.portal-bar .pb-group.open .pb-menu { opacity: 1; visibility: visible; transform: translateY(0); }
.portal-bar .pb-menu a {
  display: block; padding: 8px 10px; border-radius: 2px;
  text-transform: none; letter-spacing: 0; font-size: var(--fs--1);
  color: var(--ink);
}
.portal-bar .pb-menu a:hover { background: rgba(20,44,79,.07); color: var(--navy); text-decoration: none; }
.portal-bar .pb-menu a.here { color: var(--blue); font-weight: var(--fw-med); }
.portal-bar .pb-menu .pb-lbl {
  display: block; margin: 8px 0 2px; padding: 7px 10px 0;
  border-top: 1px solid var(--line);
  font-size: var(--fs-micro); letter-spacing: .1em; text-transform: uppercase;
  color: var(--muted); font-weight: var(--fw-med);
}
.portal-bar .pb-menu .pb-lbl:first-child { margin-top: 0; border-top: 0; padding-top: 0; }

.portal-bar .portal-bar-sep { flex: 1 0 12px; }
.portal-bar .portal-signout {
  white-space: nowrap; color: var(--blue); cursor: pointer;
  background: none; border: 0; padding: 7px 0;
  font-family: var(--font-body); font-size: var(--fs--2);
  letter-spacing: .06em; text-transform: uppercase; font-weight: var(--fw-med);
}
.portal-bar .pb-more { display: none; }

/* Below 1140px the strip becomes one button. Eight hover menus inside a
   sideways-scrolling bar is not usable with a thumb, and the row itself stops
   fitting at about 1030px, measured: below that it overflowed the wrap and
   the last groups were unreachable. Was 1060px; the search button costs about
   60px, and at 1060 the last two groups overlapped it and took its clicks. */
@media (max-width: 1140px) {
  .portal-bar .wrap { flex-wrap: wrap; gap: 0; }
  .portal-bar .pb-more {
    display: inline-flex; align-items: center; gap: 8px;
    padding: 7px 11px; margin-right: auto;
    border: 0; border-radius: 3px; background: none; cursor: pointer;
    font-family: var(--font-body); font-size: var(--fs--2);
    letter-spacing: .06em; text-transform: uppercase;
    font-weight: var(--fw-med); color: var(--navy);
  }
  .portal-bar .pb-more .chev { font-size: 9px; transition: transform .25s var(--ease); }
  .portal-bar.open .pb-more .chev { transform: rotate(180deg); }
  .portal-bar .pb-items { display: none; }
  .portal-bar.open .pb-items {
    display: flex; flex-direction: column; align-items: stretch;
    width: 100%; order: 3; gap: 0;
    padding: 6px 0 12px; border-top: 1px solid var(--line);
  }
  .portal-bar .portal-bar-sep { display: none; }
  .portal-bar .pb-group { display: block; }
  .portal-bar .pb-toggle { width: 100%; justify-content: space-between; }
  /* Inline, not floating: a phone has nowhere to float it to. */
  .portal-bar .pb-menu {
    position: static; opacity: 1; visibility: visible; transform: none;
    display: none; min-width: 0; padding: 0 0 6px 10px;
    border: 0; border-left: 2px solid var(--line); margin: 0 0 4px 11px;
    box-shadow: none; background: none;
  }
  .portal-bar .pb-group.open .pb-menu { display: block; }
  .portal-bar .pb-group:hover .pb-menu { display: none; }
  .portal-bar .pb-group.open:hover .pb-menu { display: block; }
}

/* ---------------------- Portal search -------------------------------
   The box in the bar is a button; the field is in the overlay. Everything
   below .ps-overlay is created by assets/js/portal-search.js, so nothing
   here has a counterpart in the generated HTML.

   The overlay sits at 12vh rather than centred: results grow downward, and a
   vertically centred panel jumps up and down as they do. */
/* An icon, not a 240px field. The bar is eight groups wide and already ran
   out of room at about 1030px; a field-shaped box overlapped the last two
   groups, which then sat on top of it and swallowed the click. The full
   search field lives on the hub, where there is room for it. */
.portal-bar .ps-box {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  flex: 0 0 auto; margin-right: 14px; padding: 6px 8px;
  background: none; border: 1px solid var(--line); border-radius: 4px;
  color: var(--muted); cursor: pointer;
  font-family: var(--font-body); font-size: var(--fs--2);
  letter-spacing: .06em; text-transform: uppercase; font-weight: var(--fw-med);
  transition: color .2s var(--ease), border-color .2s var(--ease),
              background .2s var(--ease);
}
.portal-bar .ps-box:hover,
.portal-bar .ps-box:focus-visible {
  color: var(--navy); border-color: var(--blue); background: #fff;
  outline: none;
}
.ps-box-icon { width: 15px; height: 15px; flex: 0 0 auto; }
.ps-box-text { position: absolute; width: 1px; height: 1px; overflow: hidden;
               clip: rect(0 0 0 0); white-space: nowrap; }
.ps-key {
  flex: 0 0 auto; padding: 1px 5px; border-radius: 3px;
  background: var(--bg-soft-2); color: var(--muted);
  font-size: var(--fs-micro); letter-spacing: .02em; white-space: nowrap;
}

html.ps-open, html.ps-open body { overflow: hidden; }

.ps-overlay {
  position: fixed; inset: 0; z-index: 200;
  display: flex; justify-content: center; align-items: flex-start;
  padding: 12vh 20px 20px;
  background: rgba(8, 15, 33, .55);
  -webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px);
  animation: ps-fade .16s var(--ease);
}
.ps-overlay[hidden] { display: none; }
@keyframes ps-fade { from { opacity: 0 } to { opacity: 1 } }

.ps-panel {
  width: 100%; max-width: 680px; max-height: 74vh;
  display: flex; flex-direction: column;
  background: #fff; border-radius: 6px;
  border-top: 3px solid var(--blue);
  box-shadow: 0 24px 70px rgba(9, 16, 36, .34);
  overflow: hidden;
}

.ps-field {
  display: flex; align-items: center; gap: 10px;
  padding: 14px 16px; border-bottom: 1px solid var(--line); flex: 0 0 auto;
}
.ps-icon { width: 18px; height: 18px; flex: 0 0 auto; color: var(--muted); }
.ps-input {
  flex: 1 1 auto; min-width: 0;
  border: 0; outline: none; background: none;
  font-family: var(--font-body); font-size: var(--fs-2);
  color: var(--ink); letter-spacing: var(--tr-snug);
}
.ps-input::placeholder { color: #9aa3b4; }
.ps-input::-webkit-search-cancel-button { display: none; }
.ps-count {
  flex: 0 0 auto; color: var(--muted); font-size: var(--fs--1); white-space: nowrap;
}
.ps-close {
  flex: 0 0 auto; padding: 3px 7px; border: 1px solid var(--line);
  border-radius: 3px; background: none; cursor: pointer;
  color: var(--muted); font-family: var(--font-body); font-size: var(--fs-micro);
}
.ps-close:hover { color: var(--navy); border-color: var(--muted); }

.ps-list { flex: 1 1 auto; overflow-y: auto; padding: 8px; }

.ps-hit {
  display: block; padding: 11px 12px; border-radius: 4px;
  color: var(--ink); text-decoration: none;
  border-left: 3px solid transparent;
}
.ps-hit:hover, .ps-hit.is-active {
  background: var(--bg-tint); border-left-color: var(--blue); text-decoration: none;
}
.ps-crumb {
  display: block; margin-bottom: 3px;
  font-size: var(--fs-micro); letter-spacing: .08em; text-transform: uppercase;
  color: var(--muted); font-weight: var(--fw-med);
}
.ps-chev { opacity: .6; }
.ps-title {
  display: block; font-family: var(--font-display);
  font-size: var(--fs-1); font-weight: var(--fw-med); color: var(--navy);
  letter-spacing: var(--tr-snug);
}
.ps-snip {
  display: block; margin-top: 3px;
  font-size: var(--fs-0); line-height: 1.55; color: var(--muted);
}
.ps-list mark, .hub-res-list mark {
  background: rgba(18, 114, 184, .15); color: inherit;
  padding: 0 1px; border-radius: 2px; font-weight: var(--fw-med);
}

.ps-empty, .ps-hint, .ps-more {
  margin: 0; padding: 18px 20px 22px;
  color: var(--muted); font-size: var(--fs-0); line-height: 1.6;
}
.ps-hint b { color: var(--navy); font-weight: var(--fw-med); }
.ps-more { padding-top: 6px; font-size: var(--fs--1); }
.ps-lbl {
  margin: 6px 0 4px; padding: 0 12px;
  font-size: var(--fs-micro); letter-spacing: .1em; text-transform: uppercase;
  color: var(--muted); font-weight: var(--fw-med);
}
.ps-recent {
  display: block; width: 100%; text-align: left;
  padding: 8px 12px; border: 0; border-radius: 4px; background: none;
  cursor: pointer; color: var(--ink);
  font-family: var(--font-body); font-size: var(--fs-0);
}
.ps-recent:hover { background: var(--bg-tint); }

.ps-foot {
  flex: 0 0 auto; display: flex; gap: 18px; margin: 0;
  padding: 9px 16px; border-top: 1px solid var(--line);
  background: var(--bg-tint);
  color: var(--muted); font-size: var(--fs-micro);
}
.ps-foot kbd {
  display: inline-block; min-width: 17px; margin-right: 3px; padding: 1px 4px;
  border: 1px solid var(--line); border-bottom-width: 2px; border-radius: 3px;
  background: #fff; font-family: inherit; font-size: 10px; text-align: center;
}

/* A hit that is a destination rather than a passage: the Order form, the
   Slack invite, Benchling. Marked so it does not read as prose. */
.ps-hit.ps-link .ps-crumb { color: var(--blue); }
.ps-ext { font-size: .8em; color: var(--muted); }

/* Where you landed, so a jump into the middle of a 200 KB handbook does not
   leave you hunting for the line. Fades out on its own. */
.ps-landed {
  animation: ps-landed 2.2s var(--ease) forwards;
  border-radius: 3px;
}
@keyframes ps-landed {
  0%, 55% { background: rgba(18, 114, 184, .14); box-shadow: 0 0 0 6px rgba(18,114,184,.14); }
  100%    { background: transparent; box-shadow: 0 0 0 6px transparent; }
}

@media (prefers-reduced-motion: reduce) {
  .ps-overlay { animation: none; }
  .ps-landed { animation-duration: .01ms; }
}

/* The bar collapses to one button here, but search is the thing people want
   most on a phone, so it stays out on the top row next to the menu button. */
@media (max-width: 1140px) {
  .portal-bar .ps-box { order: 2; margin-right: 10px; }
}
@media (max-width: 620px) {
  .ps-key { display: none; }
  .ps-overlay { padding: 0; }
  .ps-panel { max-width: none; max-height: 100%; height: 100%; border-radius: 0; }
  .ps-foot { display: none; }
}

/* ------------------------- The hub ---------------------------------
   A directory of 42 links, so it is laid out as one. The old version gave
   every entry 88px of artwork in a centred column, which came to five screens
   of scrolling and buried the handbook and the safety pages somewhere in the
   middle. Three rules now: the three most-used destinations sit above the
   fold; everything else is a dense row you can scan; and the search box and
   the section links never leave the viewport. */

.hub-pins {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 14px; margin: 0 0 26px;
}
.hub-pin {
  display: grid; grid-template-columns: 46px 1fr; grid-template-rows: auto auto;
  column-gap: 14px; align-items: center;
  padding: 16px 18px; border: 1px solid var(--line); border-radius: 10px;
  background: var(--bg-soft); transition: border-color .2s var(--ease),
    box-shadow .2s var(--ease), transform .2s var(--ease);
}
.hub-pin:hover {
  text-decoration: none; border-color: var(--navy); transform: translateY(-1px);
  box-shadow: 0 8px 22px rgba(20,44,79,.09);
}
.hub-pin img { grid-row: 1 / 3; width: 46px; height: auto; }
.hub-pin-label {
  font-family: var(--font-display); font-size: var(--fs-2);
  font-weight: var(--fw-med); color: var(--navy); line-height: 1.25;
}
.hub-pin:hover .hub-pin-label { color: var(--blue); }
.hub-pin-note {
  font-size: var(--fs--1); color: var(--muted); line-height: 1.45; margin-top: 3px;
}

/* The same three cards, inside the navy header. Translucent rather than a
   flat colour so they sit ON the band instead of punching holes in it. */
.page-head.hub-head { padding-bottom: 30px; }
.page-head.hub-head .hub-pins { margin: 24px 0 0; }
.page-head.hub-head .hub-pin {
  background: rgba(255,255,255,.07); border-color: rgba(255,255,255,.16);
  padding: 13px 16px;
}
.page-head.hub-head .hub-pin:hover {
  background: rgba(255,255,255,.12); border-color: var(--blue-light);
  box-shadow: none; transform: none;
}
.page-head.hub-head .hub-pin img { width: 38px; }
.page-head.hub-head .hub-pin { grid-template-columns: 38px 1fr; column-gap: 12px; }
.page-head.hub-head .hub-pin-label { color: #fff; font-size: var(--fs-1); }
.page-head.hub-head .hub-pin:hover .hub-pin-label { color: var(--blue-light); }
.page-head.hub-head .hub-pin-note { color: #a9bcd8; }

/* Sticky, so the search box and the eight section links are reachable from
   anywhere on the page. --chrome-top is published by stickyChrome() in
   site.js; the fallback is the wide-screen header + portal bar. */
.hub-tools {
  position: sticky; top: var(--chrome-top, 130px); z-index: 20;
  display: flex; flex-wrap: wrap; align-items: center; gap: 10px 22px;
  padding: 12px 0; margin: 0 0 18px;
  background: #fff; border-bottom: 1px solid var(--line);
}
.hub-search { position: relative; flex: 0 0 340px; max-width: 100%; }
.hub-search-btn {
  display: flex; align-items: center; gap: 10px; width: 100%; cursor: pointer;
  padding: 10px 14px; background: var(--bg-soft); text-align: left;
  border: 1px solid var(--line); border-radius: 999px;
  font-family: var(--font-body); font-size: var(--fs-0); color: var(--muted);
  transition: border-color .25s var(--ease), background .25s var(--ease),
              box-shadow .25s var(--ease);
}
.hub-search-btn svg { width: 17px; height: 17px; flex: 0 0 auto; }
.hub-search-btn > span:first-of-type { flex: 1 1 auto; }
.hub-search-btn:hover, .hub-search-btn:focus-visible {
  outline: 0; border-color: var(--blue); background: #fff; color: var(--ink);
  box-shadow: 0 0 0 3px rgba(18,114,184,.12);
}
.hub-search-key { background: #fff; }
@media (max-width: 620px) { .hub-search-key { display: none; } }
.hub-jump { display: flex; flex-wrap: wrap; gap: 6px; margin-left: auto; }
.hub-jump a {
  font-size: var(--fs--2); letter-spacing: .04em; font-weight: var(--fw-med);
  color: var(--muted); padding: 5px 10px; border-radius: 999px;
  transition: color .2s var(--ease), background .2s var(--ease);
}
.hub-jump a:hover { color: var(--navy); background: rgba(20,44,79,.07); text-decoration: none; }
.hub-jump a.here { color: #fff; background: var(--navy); }
.hub-empty { display: none; color: var(--muted); font-size: var(--fs-1); padding: 8px 0 var(--band-sm); }
.hub-empty.show { display: block; }

.tile-group { margin: 0 0 26px; }
.tile-group[hidden] { display: none; }
.hub-sec-title {
  margin: 0 0 8px; padding-bottom: 6px;
  font-family: var(--font-display); font-size: var(--fs-2); font-weight: var(--fw-med);
  color: var(--navy); border-bottom: 1px solid var(--line);
  scroll-margin-top: 200px;
}
.tile-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: 0 20px;
}
/* align-items must be start, not center: a row with no note would otherwise
   centre itself against its two-line neighbours and every column would look
   a few pixels out of step. */
.tile {
  display: grid; grid-template-columns: 30px 1fr; align-items: start;
  gap: 13px; padding: 9px 10px; margin: 0 -10px; border-radius: 8px;
  text-align: left; transition: background .16s var(--ease);
}
.tile[hidden] { display: none; }
.tile:hover { text-decoration: none; background: rgba(20,44,79,.05); }
.tile img { width: 30px; height: auto; margin-top: 1px; }
.tile-text { display: block; min-width: 0; }
.tile .tile-label {
  display: block; font-size: var(--fs-0); font-weight: var(--fw-med);
  color: var(--navy); line-height: 1.35;
}
.tile:hover .tile-label { color: var(--blue); }
.tile .tile-note {
  display: block; font-size: var(--fs--2); color: var(--muted); line-height: 1.4;
  margin-top: 1px;
}
.tile .tile-ext::after { content: " \2197"; color: var(--muted); font-weight: var(--fw-book); }

/* Embed frames: Scribe guides, Google Forms, Google Calendar */
.embed-frame { position: relative; width: 100%; border: 1px solid var(--line); background: var(--bg-soft); }
.embed-frame iframe { display: block; width: 100%; height: 100%; border: 0; }
.embed-frame.tall { height: 82vh; min-height: 620px; }
.embed-frame.form { height: 1180px; }
.embed-frame.cal { height: 620px; }
.embed-frame.cal.agenda { height: 520px; }
.embed-note { font-size: var(--fs--1); color: var(--muted); margin: 12px 0 0; }

/* Form beside calendar, the layout the Squarespace pages used */
.portal-split { display: grid; grid-template-columns: 5fr 7fr; gap: 40px; align-items: start; margin-top: 24px; }
.portal-split > * { min-width: 0; }
.portal-col-head {
  font-family: var(--font-display); font-size: var(--fs-2); font-weight: var(--fw-med);
  color: var(--navy); margin: 0 0 14px;
}

/* Stacked calendar cards */
.cal-stack { display: grid; gap: var(--band-sm); margin-top: 24px; }
/* Two across on a page that carries several calendars. The embeds hold up at
   half width, and the alternative is four full-width embeds nobody scrolls to
   the end of. Back to one column at 1100px, below which a Google week grid in
   half a column stops being readable. */
.cal-stack.two-up { grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: 40px; }
/* An agenda card is 100px shorter than a grid one, which side by side reads
   as a row that did not finish. Match them only inside the two-up grid. */
.cal-stack.two-up .embed-frame.cal.agenda { height: 620px; }
.embed-frame.sheet { height: 620px; background: #fff; }
.embed-frame.sheet iframe { padding: 18px 16px; }
@media (max-width: 1100px) { .cal-stack.two-up { grid-template-columns: 1fr; } }
/* Schedulers left, calendar right. Collapses below 1000px, where a 320px
   sidebar next to an embed leaves neither enough room. */
.cal-split {
  display: grid; grid-template-columns: minmax(0, 320px) minmax(0, 1fr);
  gap: 44px; align-items: start; margin-top: 24px;
}
.cal-split .cal-stack { margin-top: 0; }

/* ---------- /chory-calendar opens with the whole week visible ----------
   People are sent this page to look at one week and pick a slot. The sticky
   header and portal bar are already 130px of fixed overhead; a page-head band
   on top of that put two thirds of the calendar below the fold AND scrolled
   away as soon as you moved, so it cost a screen and gave nothing back. There
   is no page head here at all: the title is the sidebar h1, which costs no
   extra height, and the sharing note is fine print under the scheduler list.

   The floor is the important part. At 440px a week grid is still readable, so
   below that the page is allowed to scroll rather than shrink the calendar
   into something no one can use. 200px is the sticky chrome plus the section
   padding above the embed and a little air beneath it. */
section.block.cal-page { padding: 26px 0 34px; }
.cal-page .cal-split { margin-top: 0; }
.cal-side-title {
  font-family: var(--font-display); font-size: var(--fs-3); font-weight: 500;
  letter-spacing: -.015em; color: var(--navy); margin: 0 0 8px;
}
.cal-side-note {
  margin: 18px 0 0; padding-top: 14px; border-top: 1px solid var(--line);
  font-size: var(--fs--2); color: var(--muted); line-height: 1.55;
}
.cal-page .embed-frame.cal { height: clamp(440px, calc(100vh - 200px), 720px); }
.cal-side-lead { margin: 0 0 14px; color: var(--muted); font-size: var(--fs--1); }
@media (max-width: 1000px) { .cal-split { grid-template-columns: 1fr; gap: 32px; } }
.cal-card > .portal-col-head { margin-bottom: 12px; scroll-margin-top: 150px; }
.cal-links { list-style: none; padding: 0; margin: 18px 0 0; }
.cal-links li { padding: 11px 0; border-bottom: 1px solid var(--line); font-size: var(--fs-0); }
.cal-links li:first-child { border-top: 1px solid var(--line); }
.cal-links a { overflow-wrap: anywhere; }

/* Calendly scheduler: choices on the left, live widget on the right */
.sched { display: grid; grid-template-columns: 320px 1fr; gap: 40px; align-items: start; margin-top: 24px; }
.sched-list { display: flex; flex-direction: column; gap: 2px; }
.sched-opt {
  display: block; width: 100%; text-align: left; cursor: pointer;
  background: none; border: 0; border-top: 1px solid var(--line);
  padding: 18px 0; font-family: inherit;
  transition: border-color .25s var(--ease);
}
.sched-list .sched-opt:last-child { border-bottom: 1px solid var(--line); }
.sched-opt .sched-name {
  display: block; font-size: var(--fs-1); font-weight: var(--fw-med);
  color: var(--navy); margin-bottom: 5px;
}
.sched-opt .sched-desc { display: block; font-size: var(--fs--1); color: var(--muted); line-height: 1.6; }
.sched-opt:hover { border-top-color: var(--blue); }
.sched-opt.active { border-top-color: var(--blue); }
.sched-opt.active .sched-name { color: var(--blue); }
/* Calendly needs a real height on the parent: its iframe is height:100%, and a
   percentage height against a min-height-only box resolves to auto, which left
   the iframe at the 150px HTML default and the panel looking cut off. The
   calendly-inline-widget class on the same element is what widget.css hangs the
   iframe and spinner rules on. */
.sched-frame { height: 820px; border: 1px solid var(--line); position: relative; }
.sched-frame > iframe { display: block; width: 100%; height: 100%; border: 0; }
.sched-fallback { padding: 40px 28px; color: var(--muted); font-size: var(--fs-0); }

/* Link and document lists (lab manager, how-to index, meeting chooser) */
.doc-list { list-style: none; padding: 0; margin: 0; }
.doc-list li { border-bottom: 1px solid var(--line); }
.doc-row .doc-name {
  font-size: var(--fs-1); font-weight: var(--fw-med); color: var(--navy);
  transition: color .18s var(--ease);
}
.doc-row .doc-meta { font-size: var(--fs--1); color: var(--muted); }

/* How-to and lab-manager document lists. Each row is one link with a chevron,
   and each group carries its own spacing: previously the group heading sat
   directly on the preceding list's last hairline with no gap. */
.doc-group { max-width: 860px; margin-bottom: 52px; }
.doc-group:last-child { margin-bottom: 0; }
.doc-group > .lbl-rule { margin: 0 0 4px; }
.doc-row {
  display: flex; align-items: center; gap: 6px 18px; padding: 16px 2px 16px 0;
  text-decoration: none; transition: padding-left .18s var(--ease);
}
.doc-row:hover { padding-left: 0; box-shadow: inset 3px 0 0 var(--blue); }
.doc-row:hover .doc-name { color: var(--blue); }
.doc-row .doc-go {
  margin-left: auto; flex: none; width: 7px; height: 7px;
  border-right: 1.5px solid var(--line); border-top: 1.5px solid var(--line);
  transform: rotate(45deg); transition: border-color .18s var(--ease);
}
.doc-row:hover .doc-go { border-color: var(--blue); }
.doc-row .doc-actions {
  margin-left: auto; font-size: var(--fs-micro); letter-spacing: .08em;
  text-transform: uppercase; color: var(--muted);
  border: 1px solid var(--line); padding: 3px 8px;
}
.doc-row .doc-actions + .doc-go { margin-left: 14px; }

/* Lab maps. Both plans are transparent PNGs drawn for a light background, so
   paint white behind them rather than inheriting the band colour. */
.plan-stack { display: grid; gap: 34px; margin-top: 24px; }
.plan-stack figure { margin: 0; }
.plan-stack img { width: 100%; border: 1px solid var(--line); }
.plan-stack figcaption { font-size: var(--fs--1); color: var(--muted); margin-top: 10px; }
.plan-stack figure.plan-light img { background: var(--bg); padding: 18px; }
.plan-stack figure.plan-dark img { background: var(--navy-950); border-color: var(--navy-950); padding: 18px; }

@media (max-width: 980px) {
  .portal-split { grid-template-columns: 1fr; gap: 34px; }
  .sched { grid-template-columns: 1fr; gap: 28px; }
  .sched-frame { height: 760px; }
}
@media (max-width: 820px) {
  .portal-bar { top: 66px; }              /* .nav drops to 66px at this breakpoint */
  .hub-search { flex: 1 1 100%; }
  .hub-jump { margin-left: 0; }
}
@media (max-width: 640px) {
  .tile-grid { grid-template-columns: 1fr; }
  .hub-pins { grid-template-columns: 1fr; gap: 10px; }
  .hub-jump { display: none; }        /* the search box is the way in on a phone */
  .embed-frame.form { height: 1000px; }
  .embed-frame.tall { height: 70vh; min-height: 480px; }
  .doc-row .doc-actions { margin-left: 0; width: 100%; }
}
