/* Cerata Landing/Gate -- shared stylesheet for all pages. Plain CSS, no
   framework, no build step -- matches the project's zero-cost/no-dependency
   stance.

   Brand tokens below are the real Cerata brand spec (CRT_09 / Web Graphic
   Guidelines.md, cross-confirmed against the working landing.html/gate.html/
   quarterdeck.html prototypes in STARMAP CABIN/Interface). Per explicit
   product direction this collapses the original per-room light/dark/vibrant
   scheme (Sailmast=light, Quarterdeck=dark, Cabin=vibrant) into ONE dark
   theme site-wide -- a deliberate simplification, not an oversight. */

:root {
  --navy:      #1E2256;
  --navy-mid:  #263C85;
  --pale:      #CAD6ED;
  --off-white: #F2F2F3;
  --pink:      #F37C89;
  --font-display: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-label:   system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-mono:    ui-monospace, "SFMono-Regular", Consolas, monospace;
}

*, *::before, *::after { box-sizing: border-box; }

body {
  font-family: var(--font-display);
  font-weight: 400;
  background: var(--navy);
  color: var(--off-white);
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 8vh 1rem 5rem;
  margin: 0;
  min-height: 100vh;
}

/* Every authenticated page adds class="has-topbar" to <body> so the fixed
   topbar doesn't overlap the card. */
body.has-topbar { padding-top: calc(56px + 6vh); }

/* === TOP BAR -- home + logout, per brand guideline: plain icon (not full
   lockup) at nav size, off-white on this dark background === */
.topbar {
  position: fixed;
  top: 0; left: 0; right: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px 20px;
  background: var(--navy);
  border-bottom: 1px solid var(--navy-mid);
  z-index: 10;
}
.topbar-home {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  border: 1px solid var(--navy-mid);
  border-radius: 3px;
  background: var(--navy-mid);
  cursor: pointer;
  text-decoration: none;
  transition: background 0.15s, border-color 0.15s;
  flex-shrink: 0;
}
.topbar-home:hover { background: var(--pink); border-color: var(--pink); }
.topbar-home svg { width: 18px; height: auto; }
.topbar-home .icon-path { fill: var(--off-white); }

.topbar-logout {
  margin-top: 0;
  width: auto;
  background: var(--navy-mid);
  border: 1px solid var(--navy-mid);
  color: var(--off-white);
  padding: 0 14px;
  height: 32px;
  border-radius: 3px;
  cursor: pointer;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.85rem;
  transition: background 0.15s, border-color 0.15s;
}
.topbar-logout:hover { background: var(--pink); border-color: var(--pink); }

/* === LOGIN PAGE -- no card, just the dark background, a big centered
   emblem, and the form anchored near the bottom. Scoped to this one page;
   reset/403/admin/rooms keep the standard .card layout. === */
body.login-page {
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 4vh 1.5rem;
  gap: 1.25rem;
}
.login-emblem-wrap {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
}
.login-emblem-wrap .brand-icon-big {
  width: min(48vw, 260px);
  height: auto;
  margin: 0;
}
.login-bottom {
  width: 100%;
  max-width: 300px;
  flex-shrink: 0;
}
.login-bottom input { margin-top: 0.6rem; }
.login-bottom input:first-child { margin-top: 0; }
.login-bottom a.btn {
  display: block;
  text-align: center;
  text-decoration: none;
}
.login-bottom p {
  text-align: center;
  color: var(--pale);
  font-size: 0.85rem;
  line-height: 1.5;
  margin: 0 0 1.25rem;
}
.btn-pale {
  background: var(--pale);
  border-color: var(--pale);
  color: var(--navy);
}
.btn-pale:hover {
  background: var(--pink);
  border-color: var(--pink);
  color: var(--off-white);
}

/* === BEHAVIOR: hover-reveal action buttons ==============================
   An action button can opt into a "reveal" hover: its fill fades to
   transparent (leaving a pink outline), its resting label fades out, and
   a second, plain/explicit label fades in instead, in Pale Blue -- e.g. a
   stylized "Doe Fanatiek" reveals "Log in" on hover, so a fun brand-voice
   label never leaves a user guessing what the button actually does.

   To apply it to any <button> or <a class="btn">:
     1. Add the class "btn-reveal" alongside its normal classes.
     2. Wrap the button's visible text in <span>...</span>.
     3. Add data-hover-label="Plain explicit action" to the element.
   That's the whole contract -- no JS, pure CSS (an ::after pseudo-element
   reads the label straight from the data attribute). A button WITHOUT
   btn-reveal just keeps the plainer fill-color-swap hover defined above.
   ========================================================================= */
.btn-reveal {
  position: relative;
  overflow: hidden;
}
.btn-reveal > span {
  display: inline-block;
  transition: opacity 0.15s;
}
.btn-reveal::after {
  content: attr(data-hover-label);
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--pale);
  opacity: 0;
  transition: opacity 0.15s;
  pointer-events: none;
  font-family: var(--font-display);
  font-weight: 600;
}
.btn-reveal:hover {
  /* !important: this must always win over a modifier's own :hover fill
     (e.g. .btn-pale:hover), regardless of which is declared later --
     the reveal state is the whole point of adding this class. */
  background: transparent !important;
  border-color: var(--pink) !important;
}
.btn-reveal:hover > span { opacity: 0; }
.btn-reveal:hover::after { opacity: 1; }
.login-bottom .msg:empty { margin: 0; }

/* Kill the browser's native autofill highlight (a light, boxy fill) so an
   autofilled password field still reads as the same plain underline as
   every other input, on both the login page's plain navy background and
   the .card-based navy-mid background everywhere else. */
input:-webkit-autofill,
input:-webkit-autofill:hover,
input:-webkit-autofill:focus {
  -webkit-text-fill-color: var(--off-white);
  -webkit-box-shadow: 0 0 0 1000px var(--navy-mid) inset;
  transition: background-color 9999s ease-in-out 0s;
}
body.login-page input:-webkit-autofill,
body.login-page input:-webkit-autofill:hover,
body.login-page input:-webkit-autofill:focus {
  -webkit-box-shadow: 0 0 0 1000px var(--navy) inset;
}

/* === CARD === */
.card {
  background: var(--navy-mid);
  border: 1px solid var(--navy-mid);
  border-radius: 4px;
  padding: 2rem;
  width: 100%;
  max-width: 380px;
}
.card.wide {
  max-width: 680px;
}

/* Brand emblem -- Glaucus atlanticus silhouette, off-white on this dark
   background per the guideline's dark-bg icon-color rule. Source path:
   ExportDeBlauweDraak-05 (1).svg -- do not redraw or replace. */
.brand-icon {
  display: block;
  margin: 0 auto 1.25rem;
  width: 72px;
  height: auto;
}
.brand-icon .icon-path { fill: var(--off-white); }

h1 {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.3rem;
  margin: 0 0 1.25rem;
  color: var(--off-white);
  text-align: center;
}
.card.wide h1 { text-align: left; }

h2 {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1rem;
  color: var(--pale);
  margin: 0;
}

p { line-height: 1.5; }

label {
  display: block;
  font-family: var(--font-label);
  font-weight: 400;
  font-size: 0.85rem;
  margin: 0.9rem 0 0.3rem;
  color: var(--pale);
}

input, select {
  width: 100%;
  box-sizing: border-box;
  padding: 0.5rem 2px;
  border-radius: 2px;
  border: none;
  border-bottom: 1.5px solid var(--off-white);
  background: transparent;
  color: var(--off-white);
  font-family: var(--font-display);
  font-size: 0.9rem;
  outline: none;
  transition: border-color 0.15s;
}
input::placeholder { color: var(--off-white); opacity: 0.35; }
input:focus, select:focus { border-bottom-color: var(--pink); }
select {
  border: 1px solid var(--off-white);
  border-radius: 2px;
  padding: 0.5rem;
}

/* Native <select> dropdown popup -- background/color on the closed select
   itself is inherited from the `input, select` rule above, but the OPEN
   options list is rendered by the browser/OS chrome and ignores that
   (defaults to a plain white popup) unless `option` is styled directly.
   Mid-Blue rest, Pink Coral + white on hover/selected -- support for
   :hover/:checked on native <option> varies by browser, but Chromium
   (this sandbox, and Windows Chrome/Edge) honors it. */
select option {
  background-color: var(--navy-mid);
  color: var(--off-white);
}
select option:hover,
select option:checked,
select option:focus {
  background-color: var(--pink);
  color: #fff;
}
select optgroup {
  background-color: var(--navy-mid);
  color: var(--pale);
  font-weight: 600;
}

button, .btn {
  margin-top: 1.25rem;
  width: 100%;
  padding: 0.65rem;
  border: 1px solid var(--pink);
  border-radius: 3px;
  background: var(--pink);
  color: var(--off-white);
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.95rem;
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s;
}
button:hover, .btn:hover { background: var(--navy); border-color: var(--navy); }

.msg {
  margin-top: 1rem;
  font-family: var(--font-mono);
  font-size: 0.78rem;
  letter-spacing: 0.02em;
}
.msg.ok { color: #8fe3a8; }
.msg.err { color: var(--pink); }

a { color: var(--pale); }
a:hover { color: var(--pink); }

.secondary-links {
  margin-top: 1.5rem;
  font-size: 0.8rem;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

nav.rooms {
  display: flex;
  gap: 0.6rem;
  margin: 1rem 0 1.5rem;
  flex-wrap: wrap;
}
/* Persistent-button pattern, matched to .upload-tab (2026-09-21, Designer's
   diff-vs-upload-picker ruling): Pink Coral is the action/hover colour
   only, never a resting "this is where you are" indicator. Resting
   non-current room = inverse blue fill (navy-mid), border navy-mid.
   Hover on a non-current room = transparent + Pink Coral outline + off-
   white text, "actionable, click to switch" -- same ghost-outline hover
   as .upload-tab, not a solid pink fill. The CURRENT room sits in that
   same transparent/framed state permanently, but with an OFF-WHITE frame
   instead of Pink -- exact same "chosen but not actionable" rule as
   .upload-tab.active just above. */
nav.rooms a {
  padding: 0.35rem 0.8rem;
  border: 1px solid var(--navy-mid);
  border-radius: 3px;
  text-decoration: none;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.85rem;
  background: var(--navy-mid);
  color: var(--pale);
  transition: background 0.15s, border-color 0.15s, color 0.15s;
}
nav.rooms a:hover:not(.current) {
  background: transparent;
  border-color: var(--pink);
  color: var(--off-white);
}
nav.rooms a.current {
  background: transparent;
  border-color: var(--off-white);
  color: var(--off-white);
}

.site-footer {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.75rem;
  padding: 14px 20px;
  background: var(--navy);
  border-top: 1px solid var(--navy-mid);
  color: var(--pink);
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.85rem;
  letter-spacing: 0.05em;
  z-index: 10;
}
.footer-flourish {
  width: 26px;
  height: auto;
  fill: currentColor;
  flex-shrink: 0;
}

.stub-note {
  font-family: var(--font-mono);
  font-size: 0.78rem;
  color: var(--pale);
  border-left: 3px solid var(--pink);
  padding-left: 0.75rem;
  margin-top: 1.5rem;
  line-height: 1.6;
}

/* Admin-under-Starmap link card (item 4: folded into the page, not a
   top-level nav tab) */
.admin-link-card {
  margin-top: 1.5rem;
  padding: 1rem 1.25rem;
  border: 1px solid var(--pale);
  border-radius: 4px;
}
.admin-link-card p {
  font-size: 0.85rem;
  color: var(--pale);
  margin: 0;
}
.admin-link-card a.btn-inline {
  display: inline-block;
  margin-top: 0.75rem;
  padding: 0.5rem 1.1rem;
  border: 1px solid var(--pink);
  border-radius: 3px;
  color: var(--off-white);
  background: var(--pink);
  text-decoration: none;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.85rem;
  transition: background 0.15s, border-color 0.15s;
}
.admin-link-card a.btn-inline:hover { background: var(--navy); border-color: var(--navy); }

table {
  width: 100%;
  border-collapse: collapse;
  margin-top: 1rem;
  font-family: var(--font-mono);
  font-size: 0.8rem;
}
th, td {
  text-align: left;
  padding: 0.5rem 0.6rem;
  border-bottom: 1px solid var(--navy);
}
th {
  color: var(--pale);
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  font-size: 0.68rem;
}
th.sortable {
  cursor: pointer;
  user-select: none;
  transition: color 0.15s;
}
th.sortable:hover { color: var(--pink); }
th.sortable.sort-asc::after  { content: " \25B2"; font-size: 0.6rem; }
th.sortable.sort-desc::after { content: " \25BC"; font-size: 0.6rem; }
.badge {
  padding: 0.15rem 0.55rem;
  border-radius: 999px;
  font-size: 0.68rem;
  font-family: var(--font-mono);
}
.badge.yes { background: rgba(143, 227, 168, 0.15); color: #8fe3a8; }
.badge.no  { background: rgba(243, 124, 137, 0.15); color: var(--pink); }

.row-remove {
  margin-top: 0;
  width: auto;
  padding: 0.2rem 0.6rem;
  border: 1px solid var(--navy);
  border-radius: 3px;
  background: transparent;
  color: var(--pale);
  font-family: var(--font-mono);
  font-size: 0.72rem;
  font-weight: 400;
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s, color 0.15s;
}
.row-remove:hover { background: var(--pink); border-color: var(--pink); color: var(--off-white); }

/* === SHEET TEMPLATE ======================================================
   Page-layout template: action bar (the existing .topbar, above) + a
   "sheet" body -- left column menu + main page viewport, in a dynamic
   grid. Applied first to Galleys (2026-09-21); other rooms keep the plain
   .card.wide stub layout until/unless this is adopted there too -- these
   are new, additive class names only, nothing existing is touched, so
   Quarterdeck/Starmap/Login/Reset/Admin/403 are unaffected either way.
   ========================================================================== */

/* Optional left-side group inside .topbar (home icon + an extra action,
   e.g. Upload) -- .topbar's own space-between still pushes this group and
   .topbar-logout to opposite ends, same as when .topbar-home is a direct
   child on its own (Quarterdeck/Starmap/Admin/403/Reset). */
.topbar-left {
  display: flex;
  align-items: center;
  gap: 8px;
}
.topbar-upload {
  margin-top: 0;
  width: auto;
  display: inline-flex;
  align-items: center;
  height: 38px;
  padding: 0 14px;
  border: 1px solid var(--navy-mid);
  border-radius: 3px;
  background: var(--navy-mid);
  color: var(--off-white);
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.85rem;
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s;
}
.topbar-upload:hover { background: var(--pink); border-color: var(--pink); }

.sheet {
  width: 100%;
}
@media (max-width: 480px) {
  /* Nav went from grid-column to position:fixed (2026-09-21) -- on a
     narrow phone it would otherwise sit on top of .sheet-main's left
     edge, since main no longer reserves space for it. Drop it back into
     normal flow, full width, above main, same as before the fixed-frame
     layout existed. Not yet asked for beyond this minimal fallback. */
  .sheet-nav { position: static; width: 100%; margin-bottom: 1.25rem; }
}

/* Right-hand detail column (Monitor Wharf Imperative, 2026-09-24, Designer's
   ruling: mirror .sheet-nav on the right, index/overview/detail three
   columns, instead of widening .sheet-main or a bottom sub-viewport).
   Fixed like .sheet-nav so it doesn't scroll with the page; its own
   content scrolls internally past viewport height. Only populated by
   Starmap today, but kept general (not Starmap-scoped class names) since
   other Nexus Prisma views may want the same pattern. */
.sheet-detail {
  position: fixed;
  top: calc(56px + 6vh);
  right: 20px;
  width: 280px;
  max-height: calc(100vh - 56px - 6vh - 5rem);
  overflow-y: auto;
  background: var(--navy-mid);
  border: 1px solid var(--navy-mid);
  border-radius: 4px;
  padding: 1.25rem 1rem;
  z-index: 5;
}
.sheet-detail h3 {
  margin: 0 0 0.75rem;
  font-size: 0.8rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--pale);
}
.sheet-detail .detail-empty { color: var(--pale); font-size: 0.85rem; }
.stamp-list { font-family: var(--font-mono); font-size: 0.75rem; }
.stamp-list .stamp-row {
  padding: 0.35rem 0;
  border-bottom: 1px solid var(--navy);
}
.stamp-list .stamp-key { color: var(--pale); display: block; }
.stamp-list .stamp-value { color: var(--off-white); word-break: break-word; }
.stamp-list .stamp-section {
  margin-top: 1rem;
  padding-top: 0.5rem;
  border-top: 1px solid var(--pink);
  color: var(--pink);
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

/* Wharf table -- session rows are clickable (select + expand blob
   sub-tree); blob sub-rows are clickable (select only). Reuses the base
   table/th.sortable rules above. */
.wharf-row { cursor: pointer; }
.wharf-row:hover { background: var(--navy); }
.wharf-row.selected { background: var(--navy); }
.wharf-row.selected td:first-child { color: var(--pink); }
.wharf-blob-row { cursor: pointer; font-size: 0.72rem; color: var(--pale); }
.wharf-blob-row:hover { background: var(--navy); }
.wharf-blob-row.selected { background: var(--navy); color: var(--pink); }
.wharf-blob-row td:first-child { padding-left: 1.75rem; }
.wharf-expand-arrow { display: inline-block; width: 1em; color: var(--pale); }

@media (max-width: 1300px) {
  /* Below this, .sheet-nav (220px, left) + .sheet-main (max-width 820px,
     centered) + .sheet-detail (280px, right) start to overlap -- not yet
     asked for beyond this fallback. Detail column drops into normal flow,
     full width, below main. */
  .sheet-detail { position: static; width: 100%; margin-top: 1.25rem; max-height: none; }
}
.sheet-nav {
  position: fixed;
  top: calc(56px + 6vh);
  left: 20px;
  width: 220px;
  background: var(--navy-mid);
  border: 1px solid var(--navy-mid);
  border-radius: 4px;
  padding: 1.25rem 1rem;
  z-index: 5;
}
.sheet-nav nav.rooms { flex-direction: column; margin: 0 0 1.25rem; }
.sheet-nav nav.rooms a { text-align: left; }

.sheet-actions {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}
.sheet-action {
  display: block;
  width: 100%;
  text-align: left;
  text-decoration: none;
  padding: 0.65rem 0.85rem;
  border: 1px solid var(--navy-mid);
  background: var(--navy);
  color: var(--pale);
  font-weight: 600;
  font-size: 0.9rem;
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s, color 0.15s;
}
/* Persistent-choice/tab pattern (see Web Graphic Guidelines.md) applied
   2026-09-21 once a third sheet-action (Rower Dashboard) made these into a
   real tab set, same reasoning as the room picker and Upload activity
   tabs: resting = solid inverse-navy fill, hover-not-current = pink
   outline (the only actionable/click signal), current = permanent
   off-white outline, no hover state of its own. */
.sheet-action:hover:not(.current) {
  background: transparent;
  border-color: var(--pink);
  color: var(--off-white);
}
.sheet-action.current {
  background: transparent;
  border-color: var(--off-white);
  color: var(--off-white);
}
.sheet-main {
  background: var(--navy-mid);
  border: 1px solid var(--navy-mid);
  border-radius: 4px;
  padding: 2rem;
  min-height: 320px;
  width: 100%;
  max-width: 820px;
  margin: 0 auto;
}

/* Sheet-main screens -- Upload Rowing Session / Register Sportsapp render
   INLINE into the main viewport (2026-09-21, Designer's ruling: was a
   popup overlay on a dimmed backdrop, now uses the full screen space that
   .sheet-main already has -- the "Rowing performance" placeholder is just
   one more screen in the same rotation, not a permanent fixture).
   Exactly one .sheet-screen is .active at a time; .sheet-main's own
   background/border/padding (see above) is the only chrome now, no
   separate boxed panel nested inside it. */
.sheet-screen { display: none; }
.sheet-screen.active { display: block; }

.upload-panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 1rem;
}
.upload-panel-close {
  margin-top: 0;
  width: auto;
  padding: 0.2rem 0.6rem;
  background: transparent;
  border: 1px solid var(--navy);
  color: var(--pale);
  font-size: 0.9rem;
}
.upload-panel-close:hover { background: var(--pink); border-color: var(--pink); color: var(--off-white); }

/* Manage Sportsapps -- Connect/Disconnect toggle per provider (2026-09-21).
   Connect uses the standard action-button look (matches the reveal/hover
   language elsewhere); Disconnect (.is-connected) is deliberately NOT
   pink -- pink is the action/hover colour only per the Web Graphic
   Guidelines' Colour role rules, and "you are connected" is a resting
   state, not a call to action, same reasoning as the persistent-choice
   tab pattern. Garmin's disabled button gets a flat muted look -- no
   hover affordance, since clicking it does nothing yet. */
.sportsapp-list {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  margin: 1.25rem 0;
}
.sportsapp-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.65rem 0.85rem;
  border: 1px solid var(--navy-mid);
  background: var(--navy);
}
.sportsapp-name {
  font-weight: 600;
  font-size: 0.95rem;
}
.sportsapp-toggle {
  margin-top: 0;
  width: auto;
  padding: 0.35rem 0.85rem;
  background: var(--pink);
  border: 1px solid var(--pink);
  color: var(--off-white);
  font-size: 0.85rem;
}
.sportsapp-toggle:hover:not(:disabled) { background: transparent; border-color: var(--pink); color: var(--off-white); }
.sportsapp-toggle.is-connected {
  background: transparent;
  border-color: var(--pale);
  color: var(--pale);
}
.sportsapp-toggle.is-connected:hover:not(:disabled) { border-color: var(--pink); color: var(--off-white); }
.sportsapp-toggle:disabled {
  background: transparent;
  border-color: var(--navy-mid);
  color: var(--navy-mid);
  cursor: default;
}
.upload-tabs {
  display: flex;
  gap: 0.5rem;
  margin-bottom: 1.25rem;
}
.upload-form { display: none; }
.upload-form.active { display: block; }

/* Crew list -- expanding rower-name + position rows (Training/Practice/
   Competition forms, 2026-09-21). New row opens by pressing Enter in the
   last row's name field (see galleys.html addCrewRow) -- no remove button,
   not asked for; out of scope for now. */
.crew-list {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  margin-bottom: 0.75rem;
}
.crew-row {
  display: flex;
  gap: 0.5rem;
}
.crew-row {
  align-items: center;
}
.crew-row .crew-name {
  flex: 1;
}
/* Fixed seat label (Slag/Boeg/Stuur/seat number) -- predefined by the
   chosen boat type, not user-editable (2026-09-21, Designer: "choosing the
   boat gives the prebaked menu list and all i need to fill is the name"). */
.crew-position-label {
  flex: 0 0 auto;
  width: 4rem;
  text-align: right;
  color: var(--pale);
  font-family: var(--font-label);
  font-size: 0.85rem;
}
.crew-list:empty::before {
  content: "Choose a boat type to see the crew list";
  display: block;
  color: var(--pale);
  opacity: 0.5;
  font-size: 0.85rem;
  padding: 0.3rem 0;
}

/* Competition mm:ss:ms force fields (result time, handicap time) --
   2026-09-22, Designer's structured-result field spec. Three small number
   inputs, always visible, default 0 -- not a single free-text field. */
.time-force-field {
  display: flex;
  align-items: center;
  gap: 0.15rem;
  margin-bottom: 0.75rem;
}
.time-force-field .time-part {
  width: 3.2rem;
  text-align: center;
  -moz-appearance: textfield;
}
.time-sep {
  color: var(--pale);
  font-family: var(--font-mono);
}
.per-500-display {
  font-family: var(--font-mono);
  font-size: 0.85rem;
  color: var(--pale);
  margin-bottom: 0.75rem;
}


/* Gmail-style file attach (2026-09-21) -- the native <input type=file> is
   visually hidden but still does all the real work (native multi-select
   photo/video picker, unmodified); a styled button just triggers it, and
   picked files render as removable chips instead of the raw browser
   "Choose Files / No file chosen" text. */
.file-input-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  opacity: 0;
  pointer-events: none;
}
.file-attach-btn {
  width: auto;
  margin-top: 0;
  padding: 0.5rem 1rem;
  border: 1px solid var(--navy-mid);
  border-radius: 3px;
  background: var(--navy);
  color: var(--pale);
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.85rem;
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s, color 0.15s;
}
.file-attach-btn:hover {
  background: transparent;
  border-color: var(--pink);
  color: var(--off-white);
}
.file-attach-list {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  margin-top: 0.6rem;
}
.file-chip {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.35rem 0.6rem;
  background: var(--navy);
  border: 1px solid var(--navy-mid);
  border-radius: 3px;
  font-size: 0.8rem;
}
.file-chip-name {
  flex: 1;
  color: var(--off-white);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.file-chip-size {
  flex: 0 0 auto;
  color: var(--pale);
  opacity: 0.7;
}
.file-chip-remove {
  flex: 0 0 auto;
  width: 1.4rem;
  height: 1.4rem;
  margin-top: 0;
  padding: 0;
  border: none;
  border-radius: 2px;
  background: transparent;
  color: var(--pale);
  font-size: 1rem;
  line-height: 1;
  cursor: pointer;
}
.file-chip-remove:hover {
  background: var(--pink);
  color: var(--off-white);
}

/* === GALLEYS ITERATION 2 (2026-09-21) =====================================
   Designer-reviewed changes on top of the sheet template above: room nav
   moved from the sidebar into the topbar centre, inverted-colour topbar
   icon buttons (home + new logout icon), and a persistent-reveal state for
   the upload-tab "chosen" button. All additive/new class names -- nothing
   above this block is touched, so Quarterdeck/Starmap/Login/Reset/Admin/403
   remain exactly as before. Scoped to Galleys only for now, same as the
   sheet template itself. ========================================== */

/* Centred room nav inside the topbar. .topbar is already `position: fixed`,
   which is itself a containing block for an absolutely-positioned
   descendant -- so this centres correctly regardless of how wide
   .topbar-left or the logout button are, without touching .topbar's own
   flex/space-between rule (which Quarterdeck/Starmap/Admin/403/Reset still
   rely on for their plain 2-child layout). */
.topbar-center-nav {
  /* top:0/bottom:0 + flex align-items:center vertically centers within the
     full topbar height -- more robust than top:50%/translateY(-50%), which
     measured ~16px off in testing (2026-09-21) despite computing a correct
     transform matrix; not worth chasing why, this approach sidesteps it. */
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  top: 0;
  bottom: 0;
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin: 0;
}

/* Inverted-colour topbar icon buttons -- Off-White bg + Navy Deep icon at
   rest (the Logotype section's own "light background: Navy Deep icon"
   variant), Pink Coral bg + Off-White icon on hover (the universal hover
   rule). Compound selectors so this wins on specificity regardless of
   source order -- style.css already had one real bug from an equal-
   specificity source-order collision (.btn-pale vs the generic button/.btn
   rule, found 2026-09-21); not repeating that mistake here. */
.topbar-home.topbar-icon-inverse,
.topbar-logout-icon {
  background: var(--off-white);
  border-color: var(--off-white);
}
.topbar-home.topbar-icon-inverse:hover,
.topbar-logout-icon:hover {
  background: var(--pink);
  border-color: var(--pink);
}
.topbar-home.topbar-icon-inverse .icon-path { fill: var(--navy); }
.topbar-home.topbar-icon-inverse:hover .icon-path { fill: var(--off-white); }

.topbar-logout-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  padding: 0;
  margin-top: 0;
  border: 1px solid var(--off-white);
  border-radius: 3px;
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s;
}
.topbar-logout-icon svg { width: 20px; height: 20px; }
.topbar-logout-icon .icon-stroke { stroke: var(--navy); transition: stroke 0.15s; }
.topbar-logout-icon:hover .icon-stroke { stroke: var(--off-white); }

/* .btn-reveal's ::after fills the button box (inset:0) rather than sizing
   to its own text, so a fixed 38x38 icon square clips "Home"/"Log out" at
   the default font-size -- these two buttons widen on hover (transitioning
   width, not just fading content) so the revealed label has room. Height/
   position stay put; nothing else about .btn-reveal is touched, so the
   Login page's own reveal buttons (already sized to their text) are
   unaffected. */
.topbar-home.btn-reveal::after,
.topbar-logout-icon.btn-reveal::after {
  font-size: 0.8rem;
  white-space: nowrap;
}
.topbar-home.btn-reveal { transition: background 0.15s, border-color 0.15s, width 0.15s; }
.topbar-logout-icon.btn-reveal { transition: background 0.15s, border-color 0.15s, width 0.15s; }
.topbar-home.btn-reveal:hover { width: 4.5rem; }
.topbar-logout-icon.btn-reveal:hover { width: 5.5rem; }

/* Upload tabs -- persistent-reveal "chosen" state (2026-09-21 test, pending
   Designer sign-off before this becomes a documented guideline). Base
   button-reveal mechanic (background: var(--navy) at rest -> background
   goes transparent + Pink Coral frame + Off-White text on hover) applies
   to whichever tab is NOT chosen -- Pink Coral there means "actionable,
   click to switch". The CHOSEN tab sits permanently in that same
   transparent/framed state, but with an OFF-WHITE frame instead of Pink --
   Pink Coral is reserved for the action/hover role per this doc's Colour
   role rules, so a chosen-but-not-actionable state deliberately does not
   use it. */
.upload-tab {
  flex: 1;
  margin-top: 0;
  padding: 0.5rem;
  border: 1px solid var(--navy-mid);
  background: var(--navy);
  color: var(--pale);
  font-weight: 600;
  font-size: 0.85rem;
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s, color 0.15s;
}
.upload-tab:hover:not(.active) {
  background: transparent;
  border-color: var(--pink);
  color: var(--off-white);
}
.upload-tab.active {
  background: transparent;
  border-color: var(--off-white);
  color: var(--off-white);
}

/* Idle-guard overlay (2026-09-30, Grenadier "loud logout") -- full-screen
   prompt injected by public/idle-guard.js 30s before the server's idle
   timeout ends the session. Uses the existing .btn-reveal contract (base
   label visible, plain-language action on hover); no new tokens. */
.idle-overlay {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(30, 34, 86, 0.94);
  padding: 1rem;
}
.idle-card {
  background: var(--navy-mid);
  border: 1px solid var(--pale);
  padding: 2rem 2.25rem;
  max-width: 46rem;
  width: 100%;
  text-align: center;
}
.idle-card h2 { margin: 0 0 0.75rem; font-weight: 600; }
.idle-card p { margin: 0 0 1.5rem; color: var(--pale); }
.idle-count { color: var(--off-white); font-family: var(--font-mono); font-size: 1.25rem; }
.idle-stage { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 1.25rem; margin: 0 0 1rem; }
.idle-btn { min-height: 2.75rem; width: 100%; white-space: normal; align-self: start; margin-top: 1.25rem; } /* sits level with the wings */
.idle-card p { margin: 0; }
/* Narrow screens: dragon on top, the two buttons stacked beneath it. */
@media (max-width: 40rem) {
  .idle-stage { grid-template-columns: 1fr; }
  .idle-btn { margin-top: 0; }
  .idle-stage .idle-dragon { order: -1; margin: 0 auto; width: 10rem; }
}

/* Idle-guard dragon emblem (2026-09-30, Designer: "just to make the app more
   cute") -- the blue-dragon glyph glows Off-White -> Pink Coral, on repeat,
   same white-to-pink pulse Publish Row Session specifies for the sync window. */
.idle-dragon { width: 13.5rem; height: auto; display: block; }
.idle-dragon path {
  fill: var(--off-white);
  animation: idle-glow 2s ease-in-out infinite;
}
@keyframes idle-glow {
  0%, 100% { fill: var(--off-white); filter: drop-shadow(0 0 4px rgba(242, 242, 243, 0.7)); }
  50%      { fill: var(--pink);      filter: drop-shadow(0 0 12px var(--pink)); }
}
@media (prefers-reduced-motion: reduce) { .idle-dragon path { animation: none; } }
