/* Responsive shell for the consumer app - see
   docs/ui_design_navigation.md for the design this implements.

   Same server-rendered markup at every width; only layout/nav mechanism
   changes at the two breakpoints (600px, 1024px). This first pass covers
   the Home screen only - Timeline/Documents/Photos/Messages nav items are
   placeholders until those routes exist. */

:root {
  --color-bg: #f5f6f7;
  --color-surface: #ffffff;
  --color-border: #e0e2e5;
  --color-text: #1c1f23;
  --color-text-muted: #63696f;
  /* Exact-matched to the public website's palette (Website\styles.css'
     --glow-dark-green/--glow-amber) for family resemblance, not just a
     similar green picked independently. */
  --color-accent: #1f6b3f;
  --color-accent-contrast: #ffffff;
  --color-warm: #e8b34d;
  --color-warm-contrast: #3a2a05;
  /* Pane-cascade depth cues (list -> detail -> context) - light tints of
     --color-accent, progressively stronger, so drilling in reads as
     "deeper into the brand green" rather than 3 flat panels that happen to
     sit next to each other. */
  --color-pane-detail: #f0f7f3;
  --color-pane-context: #e5f1ea;
  /* Messages: a quiet per-role identity cue on received bubbles (see
     .chat-bubble.role-* below) - blue for Architect since it's the one
     role guaranteed on every project, amber for every other provider type
     so the palette doesn't multiply per provider. Neither collides with
     --color-accent (reserved for the consumer's own sent bubbles). */
  --color-role-architect: #2f6fb0;
  --nav-width: 220px;
  --header-height: 64px;
  --bottom-nav-height: 60px;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
  color: var(--color-text);
  background: var(--color-bg);
}

a { color: var(--color-accent); }

/* ---- App bar (sticky header, always present) ---- */

.app-header {
  position: sticky;
  /* Sticks 16px below the viewport top, not flush - keeps the header
     reading as a floating rounded card (matching list-pane/detail-pane
     etc) even once scrolled, instead of snapping flush with its rounded
     corners suddenly clipped square against the viewport edge. */
  top: 16px;
  z-index: 10;
  height: var(--header-height);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 0 16px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: 10px;
  margin-bottom: 16px;
}

.app-header .titles {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
}

.back-link {
  text-decoration: none;
  font-size: 1.2rem;
  color: var(--color-text);
  flex-shrink: 0;
}

@media (min-width: 600px) {
  .back-link { display: none; } /* desktop never navigates away, so no back link */
}

.app-header .titles h1 {
  margin: 0;
  font-size: 1.1rem;
}

.phase-badge {
  display: inline-block;
  vertical-align: middle;
  font-size: 0.65rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--color-accent);
  color: var(--color-accent-contrast);
}

.app-header .titles .subtitle {
  margin: 0;
  font-size: 0.8rem;
  color: var(--color-text-muted);
}

.app-header .actions {
  display: flex;
  align-items: center;
  gap: 12px;
}

.icon-button {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  border: 1px solid var(--color-border);
  background: var(--color-surface);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1rem;
}

/* ---- Shell layout ---- */

.app-shell {
  display: flex;
  min-height: 100vh;
}

.sidebar-nav {
  display: none;
}

.main-content {
  flex: 1;
  padding: 16px;
  padding-bottom: calc(var(--bottom-nav-height) + 16px);
}

.bottom-nav {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  height: var(--bottom-nav-height);
  display: flex;
  background: var(--color-surface);
  border-top: 1px solid var(--color-border);
}

.bottom-nav a, .sidebar-nav a {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  text-decoration: none;
  color: var(--color-text-muted);
  font-size: 0.7rem;
}

.sidebar-nav a {
  flex: none;
  flex-direction: row;
  justify-content: flex-start;
  gap: 10px;
  padding: 10px 16px;
  font-size: 0.9rem;
  border-radius: 8px;
}

.sidebar-nav a[aria-current="page"],
.bottom-nav a[aria-current="page"] {
  color: var(--color-accent);
  font-weight: 600;
}

/* Fixtures & Fittings / Technologies / Ideas Board become read-only from
   the Technical phase onward - not enforced yet (none of the 3 screens
   exist), just previewed here so the rule is visible before it matters. */
.nav-locked {
  opacity: 0.6;
}

@media (min-width: 600px) {
  .bottom-nav, .nav-sheet, .nav-sheet-backdrop { display: none !important; } /* mobile-only */

  .sidebar-nav {
    display: flex;
    flex-direction: column;
    gap: 4px;
    width: var(--nav-width);
    flex-shrink: 0;
    padding: 16px 8px;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: 10px;
    /* Top margin matches .app-header's own top offset (main-content's
       16px padding-top) so the two cards' top edges line up; left margin
       insets it from the viewport edge the same way main-content's own
       padding already insets the header. */
    margin: 16px 0 16px 16px;
    /* Own scrollbar rather than growing to match .content-scroll's height
       (the default flex stretch behaviour) - without this the whole card
       grows as tall as whatever page content sits next to it, and empty
       space or a nav-item overflow both look wrong. 32px = its own 16px
       top + 16px bottom margin. */
    max-height: calc(100vh - 32px);
    overflow-y: auto;
  }

  .main-content { padding-bottom: 16px; }

  /* Everything below the sticky header scrolls in its own box instead of
     the whole document - the header and sidebar-nav (both siblings of this,
     not inside it) then never move at all, matching the pane-cascade panes'
     own "only I scroll" treatment below (same calc(100vh - header - 48px)
     formula: 16px main-content padding-top + header's 64px + its 16px
     margin-bottom + main-content's 16px padding-bottom = 48px of chrome
     around the header, same on every page). Scoped to desktop only - mobile
     has no sidebar to protect and its bottom-nav is already position:fixed,
     so the plain whole-page scroll it already had is fine as-is. */
  .content-scroll {
    max-height: calc(100vh - var(--header-height) - 48px);
    overflow-y: auto;
  }
}

/* ---- Mobile "More" bottom sheet - everything that didn't fit in the
   bottom nav's 4 primary + More slots (see PrimaryNavIndexesForPhase in
   ConsumerSiteUnit.pas). Not a hamburger menu - docs\ui_design_navigation.md
   rules those out; this is reached via the bottom nav's own "More" tab. ---- */

.nav-sheet-backdrop {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.4);
  z-index: 20;
}

.nav-sheet-backdrop.open { display: block; }

.nav-sheet {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  transform: translateY(100%);
  transition: transform 0.2s ease-out;
  background: var(--color-surface);
  border-radius: 16px 16px 0 0;
  padding: 8px 0 max(16px, env(safe-area-inset-bottom));
  z-index: 21;
  max-height: 70vh;
  overflow-y: auto;
}

.nav-sheet.open { transform: translateY(0); }

.nav-sheet-handle {
  width: 40px;
  height: 4px;
  background: var(--color-border);
  border-radius: 999px;
  margin: 8px auto 12px;
}

.nav-sheet a {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 20px;
  text-decoration: none;
  color: var(--color-text);
  font-size: 0.95rem;
}

.nav-sheet a.nav-locked { color: var(--color-text-muted); }

/* ---- Home screen ---- */

.home-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 16px;
}

@media (min-width: 1024px) {
  .home-grid {
    grid-template-columns: repeat(2, 1fr);
    align-items: start;
  }
  .home-grid .block-team { grid-column: 2; grid-row: 1 / span 2; }
}

.block {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: 10px;
  padding: 16px;
}

/* Client Feedback's "providers to review" block sits standalone above the
   pane-cascade (not inside .home-grid, so no grid gap to rely on). */
.block-to-review { margin-bottom: 16px; }

.block h2 {
  margin: 0 0 12px;
  font-size: 1rem;
}

.empty-state {
  color: var(--color-text-muted);
  font-size: 0.9rem;
}

.phase-strip {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  list-style: none;
  margin: 12px 0 0;
  padding: 0;
}

.phase-strip li {
  padding: 4px 10px;
  border-radius: 999px;
  font-size: 0.75rem;
  border: 1px solid var(--color-border);
  color: var(--color-text-muted);
}

.phase-strip li.is-complete {
  background: var(--color-accent);
  color: var(--color-accent-contrast);
  border-color: var(--color-accent);
}

.phase-strip li.is-current {
  border-color: var(--color-accent);
  color: var(--color-accent);
  font-weight: 600;
}

.progress-bar {
  height: 8px;
  border-radius: 999px;
  background: var(--color-border);
  overflow: hidden;
  margin-top: 8px;
}

.progress-bar > span {
  display: block;
  height: 100%;
  background: var(--color-accent);
}

.quick-access .tile {
  flex: 1;
  text-align: center;
  padding: 12px;
  border-radius: 10px;
  border: 1px dashed var(--color-border);
  color: var(--color-text-muted);
  font-size: 0.85rem;
}

.team-contact {
  padding: 8px 0;
  border-bottom: 1px solid var(--color-border);
}

.team-contact:last-child { border-bottom: none; }

.team-contact .provider-type {
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--color-text-muted);
}

/* ---- Pane cascade (Timeline, Documents): list -> detail -> context ----
   Same markup at every width (docs/ui_design_navigation.md: "only the page
   layout/CSS changes"). data-level on .pane-cascade says which single pane
   is shown on a real mobile page-navigation to that level; at >=600px all
   panes relevant to that width show together via CSS grid regardless of
   data-level. */

.pane-cascade .list-pane,
.pane-cascade .detail-pane,
.pane-cascade .context-panel {
  display: none;
}

/* Depth cues: each pane gets its own surface, progressively tinted
   greener, so it reads as 3 distinct layers (list -> detail -> context)
   rather than one continuous background - true on mobile too, where only
   one pane shows at a time, as a "you're now a level deeper" signal each
   time you navigate in. */
.pane-cascade .list-pane {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: 10px;
  padding: 12px;
}

.pane-cascade .detail-pane {
  background: var(--color-pane-detail);
  border: 1px solid var(--color-border);
  border-radius: 10px;
  padding: 16px;
}

.pane-cascade .context-panel {
  background: var(--color-pane-context);
  border: 1px solid var(--color-border);
  border-radius: 10px;
  padding: 16px;
}

.pane-cascade[data-level="1"] .list-pane { display: block; }
.pane-cascade[data-level="2"] .detail-pane { display: block; }
.pane-cascade[data-level="3"] .context-panel { display: block; }

@media (min-width: 600px) {
  .pane-cascade {
    display: grid;
    grid-template-columns: 280px 1fr;
    gap: 16px;
    align-items: start;
  }
  .pane-cascade .list-pane { display: block; }
  .pane-cascade .detail-pane { display: block; }
  .pane-cascade .context-panel { display: none; }

  /* Each pane scrolls independently instead of the whole page scrolling
     as one unit - otherwise scrolling column 1 down to reach a lower
     item (e.g. the 5th phase) drags columns 2/3 out of view along with
     it, since they all share one page-level scroll and start at the same
     row top. Capping height to the viewport below the sticky header
     keeps every column's top pinned in place regardless of how far any
     one of them is scrolled. */
  .pane-cascade .list-pane,
  .pane-cascade .detail-pane,
  .pane-cascade .context-panel {
    /* 48px = main-content's 16px top padding + the header's own 16px
       margin-bottom, both now part of the chrome above these panes. */
    max-height: calc(100vh - var(--header-height) - 48px);
    overflow-y: auto;
  }
}

@media (min-width: 1024px) {
  .pane-cascade {
    grid-template-columns: 280px 1fr 320px;
  }
  .pane-cascade .context-panel { display: block; }
}

/* ---- Pane cascade, 2-level (Technologies): list -> detail, no third
   context-panel level - unlike Fixtures/Timeline/Documents, there's
   nothing to drill into past a single technology's own detail, so this
   stops at 2 columns at every width instead of gaining a 3rd at
   >=1024px. ---- */

.pane-cascade-2 .list-pane,
.pane-cascade-2 .detail-pane {
  display: none;
}

.pane-cascade-2 .list-pane {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: 10px;
  padding: 12px;
}

.pane-cascade-2 .detail-pane {
  background: var(--color-pane-detail);
  border: 1px solid var(--color-border);
  border-radius: 10px;
  padding: 16px;
}

.pane-cascade-2[data-level="1"] .list-pane { display: block; }
.pane-cascade-2[data-level="2"] .detail-pane { display: block; }

@media (min-width: 600px) {
  .pane-cascade-2 {
    display: grid;
    grid-template-columns: 280px 1fr;
    gap: 16px;
    align-items: start;
  }
  .pane-cascade-2 .list-pane { display: block; }
  .pane-cascade-2 .detail-pane { display: block; }

  /* Same independent-scroll reasoning as .pane-cascade - see its comment. */
  .pane-cascade-2 .list-pane,
  .pane-cascade-2 .detail-pane {
    max-height: calc(100vh - var(--header-height) - 48px);
    overflow-y: auto;
  }
}

.list-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 12px;
  border-radius: 8px;
  text-decoration: none;
  color: inherit;
  border: 1px solid transparent;
}

.list-row:hover { background: var(--color-bg); }

.list-row[aria-current="true"] {
  border-color: var(--color-accent);
  background: var(--color-bg);
}

.list-row .list-row-title { font-weight: 600; }
.list-row .list-row-meta { font-size: 0.8rem; color: var(--color-text-muted); }
.list-row .list-row-count {
  font-size: 0.8rem;
  color: var(--color-text-muted);
  flex-shrink: 0;
}

/* ---- Level-1 list-pane items: card-wash treatment ----
   Level 1 (list-pane) is always a vertical column of several items -
   phases, categories, projects - which as plain rows can be misread as
   one continuous block of text. Giving each item its own tinted card
   (reusing the pane-detail/pane-context depth-cue tokens, so hovering or
   selecting reads as "one step deeper", same as the pane background
   cues) makes them read as distinct, clickable entries instead. Scoped to
   .list-pane so Level 2/3 rows (documents-in-category, milestones inside
   an expanded phase, etc) keep their existing plain-row styling. */

.list-pane .list-row {
  background: var(--color-pane-detail);
  border-color: var(--color-border);
  margin-bottom: 8px;
  /* .checklist li is a flex row, which sizes a flex-item anchor to fit its
     own content by default - short items (e.g. "Kitchen") end up as
     narrow cards while longer ones stretch wide, an inconsistent look
     across screens. Forcing full width makes every card match the
     phase-list cards' width (a block element, full width by default). */
  width: 100%;
}

/* Not .list-row:last-child - each checklist <li> has exactly one child
   (the row itself), so the row is always both :first-child and
   :last-child of its own <li>, which zeroed out every card's spacing
   instead of just the actual last item's. Target the <li> that's last
   instead. */
.list-pane li:last-child > .list-row { margin-bottom: 0; }

.list-pane .list-row:hover { background: var(--color-pane-context); }

.list-pane .list-row[aria-current="true"] { background: var(--color-pane-context); }

/* Only direct children of list-pane - not the nested milestone checklist
   that some phase-list cards stack inside themselves, which should keep
   its plain hairline-divider look rather than becoming mini cards. */
.list-pane > .checklist > li {
  border-bottom: none;
  padding: 0;
}

/* Timeline's phase-list stacks extra content (progress bar, milestones,
   photo/doc line) under the title inside each <li> - the whole <li> is
   "the item" here, not just the nested .list-row title, so the card wash
   goes on the <li> and the inner .list-row reverts to a plain title strip
   inside it rather than doubling up as a card-within-a-card. */
.list-pane .phase-list > li {
  background: var(--color-pane-detail);
  border: 1px solid var(--color-border);
  border-radius: 8px;
  padding: 10px 12px 14px;
}

.list-pane .phase-list > li:last-child {
  border-bottom: 1px solid var(--color-border);
  margin-bottom: 0;
}

.list-pane .phase-list .list-row {
  background: none;
  margin-bottom: 0;
  padding: 8px 4px;
}

.list-pane .phase-list .list-row:hover { background: none; }

.list-pane .phase-list .list-row[aria-current="true"] {
  background: none;
  border-color: var(--color-accent);
}

.status-badge {
  display: inline-block;
  padding: 2px 10px;
  border-radius: 999px;
  font-size: 0.75rem;
  border: 1px solid var(--color-border);
  color: var(--color-text-muted);
}

.status-badge.is-complete { background: var(--color-accent); color: var(--color-accent-contrast); border-color: var(--color-accent); }
.status-badge.is-inprogress { background: var(--color-warm); color: var(--color-warm-contrast); border-color: var(--color-warm); font-weight: 600; }
.status-badge.is-rejected { color: #b3261e; border-color: #b3261e; }

.idea-thumbnail {
  width: 100%;
  max-width: 320px;
  max-height: 200px;
  object-fit: cover;
  border-radius: 8px;
  display: block;
  margin: 8px 0;
}

/* Preserves line breaks from the now-multi-line description composer -
   same reasoning as .bubble-text's own pre-wrap (which idea comments
   already inherit, being built from that same class). Without this, a
   description typed across several lines runs back together as one
   paragraph once rendered. */
.idea-description { white-space: pre-wrap; }

.list-row .idea-thumbnail-small {
  width: 48px;
  height: 48px;
  object-fit: cover;
  border-radius: 6px;
  flex-shrink: 0;
}

/* Timeline milestone panel's per-task photos - the context-panel column is
   narrow, so small square tiles that wrap, not a full-width grid. */
.milestone-photo-list {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 12px;
}

.milestone-photo-thumb {
  width: 72px;
  height: 72px;
  object-fit: cover;
  border-radius: 8px;
  display: block;
}

/* Idea tags: a filter chip row (some clickable/current) and small
   read-only chips shown on list rows / an idea's own detail. */

.tag-filter-row {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: 12px;
}

.tag-chip {
  display: inline-block;
  padding: 3px 10px;
  border-radius: 999px;
  font-size: 0.75rem;
  border: 1px solid var(--color-border);
  color: var(--color-text-muted);
  text-decoration: none;
  background: var(--color-surface);
}

a.tag-chip:hover { border-color: var(--color-accent); color: var(--color-accent); }

.tag-chip[aria-current="true"] {
  background: var(--color-accent);
  color: var(--color-accent-contrast);
  border-color: var(--color-accent);
}

.idea-tags { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 4px; }

.tag-checkboxes { display: flex; flex-wrap: wrap; gap: 12px; }

.tag-checkboxes label {
  display: flex;
  align-items: center;
  gap: 6px;
  font-weight: 400;
  font-size: 0.9rem;
}

.checklist { list-style: none; margin: 0; padding: 0; }

.checklist li {
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding: 8px 0;
  border-bottom: 1px solid var(--color-border);
}

.checklist li:last-child { border-bottom: none; }
.checklist .task-date { margin-left: auto; font-size: 0.8rem; color: var(--color-text-muted); }

/* Timeline's phase list - unlike .checklist, each <li> here can stack
   several block children (link, progress bar, condensed milestone list,
   photo/doc line) for the current stage, so it stays in normal block flow
   rather than .checklist's flex row. */
.phase-list { list-style: none; margin: 0; padding: 0; }

.phase-list > li {
  padding: 4px 0 12px;
  border-bottom: 1px solid var(--color-border);
  margin-bottom: 8px;
}

.phase-list > li:last-child { border-bottom: none; margin-bottom: 0; }
.phase-list .list-row { padding: 8px 4px; }
.phase-list .checklist { margin: 8px 0; }
.phase-list > li > p { margin: 8px 0 0; }

/* Client Feedback: same reasoning as .phase-list - each review/to-review
   <li> stacks a title, a meta line and a body paragraph/link, which
   .checklist's flex-row <li> would lay out side by side instead of. */
.review-list { list-style: none; margin: 0; padding: 0; }

.review-list > li {
  padding: 12px 0;
  border-bottom: 1px solid var(--color-border);
}

.review-list > li:last-child { border-bottom: none; }
.review-list p { margin: 6px 0 0; }

.gantt-strip { list-style: none; margin: 0; padding: 0; }

.gantt-strip li {
  padding: 8px 0;
  border-bottom: 1px solid var(--color-border);
  font-size: 0.85rem;
}

.gantt-strip li:last-child { border-bottom: none; }
.gantt-strip .gantt-dates { color: var(--color-text-muted); font-size: 0.75rem; }

/* ---- Messages: two columns (thread + info), never three ---- */

.chat-shell { display: block; }

.chat-thread {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: 10px;
  padding: 16px;
  display: flex;
  flex-direction: column;
  min-height: 60vh;
}

.chat-messages { flex: 1; overflow-y: auto; display: flex; flex-direction: column; gap: 10px; }

.chat-bubble { max-width: 75%; }
.chat-bubble.is-received { align-self: flex-start; }
.chat-bubble.is-sent { align-self: flex-end; text-align: right; }

.chat-bubble .bubble-meta { font-size: 0.75rem; color: var(--color-text-muted); margin-bottom: 2px; }

.chat-bubble .bubble-text {
  display: inline-block;
  padding: 8px 12px;
  border-radius: 12px;
  background: var(--color-bg);
  /* Preserves line breaks from the multi-line composer - without this,
     HTML collapses the message's actual newlines and a 3-line message
     you typed and sent renders back as one run-on line. */
  white-space: pre-wrap;
  text-align: left;
  /* Attachment chips are real <a href> links now (so they're clickable),
     not just the plain message-text div - reset anchor defaults so a
     linked chip still looks like a chip, not a generic blue underlined
     link. */
  text-decoration: none;
  color: inherit;
}

.chat-bubble .bubble-text:hover { opacity: 0.85; }

.chat-bubble.is-sent .bubble-text { background: var(--color-accent); color: var(--color-accent-contrast); }

/* Received-bubble role stripe - not a full-bubble tint (that turns a
   3+-participant thread into a wall of colour), just enough to tell
   Architect and other-provider messages apart at a glance without
   reading the name each time. Scoped to .bubble-message (the actual
   message text) only, not the photo/document attachment chips below it -
   those stay plain. Not rounded on the left - see the "no rounded
   corners on a single-sided border" rule this mirrors. */
.chat-bubble.role-architect .bubble-message {
  border-left: 3px solid var(--color-role-architect);
  border-radius: 0 12px 12px 0;
}

.chat-bubble.role-provider .bubble-message {
  border-left: 3px solid var(--color-warm);
  border-radius: 0 12px 12px 0;
}

.chat-date-divider {
  text-align: center;
  font-size: 0.75rem;
  color: var(--color-text-muted);
  margin: 8px 0;
}

/* Messages' attach toggle - sits inside .chat-composer's own flex row,
   between the textarea and Send (not a separate block above it). Opens
   as a popover ABOVE the composer - same position:absolute/z-index
   pattern as the header's .pm-menu-dropdown, just anchored to the
   bottom instead of the top since this sits at the bottom of the
   screen - rather than pushing the row's layout around, since an opened
   <details> panel doesn't play well as a flex child (its content wants
   full width, the row would squeeze it). */
.attach-details {
  position: relative;
  flex-shrink: 0;
}

.attach-toggle {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  /* Bolder than the header's own icon-buttons (bell/account/folder) -
     a heavier 2px border and slightly larger glyph, since this is the
     one icon-button inline with the composer's input and Send button
     and needs to read clearly at a glance, not blend in as chrome. */
  border: 2px solid var(--color-text);
  background: var(--color-surface);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.2rem;
  cursor: pointer;
  list-style: none;
}

.attach-toggle::-webkit-details-marker { display: none; }

.attach-details[open] .attach-toggle {
  border-color: var(--color-accent);
  color: var(--color-accent);
}

.attach-panel {
  position: absolute;
  bottom: calc(100% + 8px);
  right: 0;
  z-index: 20;
  width: 260px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: 10px;
  padding: 12px;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
}

.attach-panel .form-field { margin-top: 12px; margin-bottom: 0; }
.attach-panel .form-field:first-child { margin-top: 0; }

.chat-composer {
  display: flex;
  /* flex-end (not the default stretch) so the paperclip/Send button stay
     anchored to the bottom of the composer as the textarea grows across
     multiple lines, instead of stretching to match its height. */
  align-items: flex-end;
  gap: 8px;
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px solid var(--color-border);
}

.chat-composer input[type="text"] {
  flex: 1;
  padding: 10px 12px;
  border-radius: 999px;
  border: 1px solid var(--color-border);
  font: inherit;
}

/* Messages' own composer (chat-composer-input) - a textarea, not the
   single-line input above (kept for any other reuse; nothing currently
   uses it single-line since the Ideas Board comment box and "new idea"
   description field both now share this same class - see their own
   comments below). Return now inserts a newline (a textarea's native
   behaviour) instead of submitting - WhatsApp-like multi-line entry, Send
   is the only way to actually send. Grows with content via app.js up to
   max-height, then scrolls internally. Reused wherever the app wants
   this same look/behaviour, not just inside .chat-composer's flex bar
   (see the .form-field override below for the "new idea" form). */
.chat-composer-input {
  flex: 1;
  min-height: 40px;
  max-height: 120px;
  padding: 10px 14px;
  border-radius: 20px;
  border: 1px solid var(--color-border);
  font: inherit;
  line-height: 1.4;
  resize: none;
  overflow-y: auto;
}

.chat-composer-input:focus {
  outline: 2px solid var(--color-accent);
  outline-offset: 1px;
}

.chat-composer button {
  padding: 0 18px;
  height: 40px;
  border-radius: 999px;
  border: none;
  background: var(--color-accent);
  color: var(--color-accent-contrast);
  font-weight: 600;
  flex-shrink: 0;
}

.chat-info {
  display: none;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: 10px;
  padding: 16px;
  margin-top: 16px;
}

/* ---- Forms (Client Feedback's "write a review" today - reusable for any
   future form) ---- */

.review-form {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: 10px;
  padding: 20px;
  max-width: 480px;
}

.form-field { margin-bottom: 18px; }

/* File-vs-link toggle on the Documents upload form (BuildDocumentUploadFormHtml)
   - plain radios in a row, not styled as buttons/pills, since this is a
   one-off choice made once per upload, not a repeated navigation control. */
.radio-row {
  display: flex;
  gap: 20px;
  font-size: 0.95rem;
}

.radio-row label {
  display: flex;
  align-items: center;
  gap: 6px;
  font-weight: 400;
  cursor: pointer;
}

.form-field label {
  display: block;
  font-weight: 600;
  font-size: 0.9rem;
  margin-bottom: 6px;
}

.form-field select,
.form-field textarea,
.form-field input[type="text"],
.form-field input[type="url"],
.form-field input[type="file"] {
  width: 100%;
  padding: 10px 12px;
  border-radius: 8px;
  border: 1px solid var(--color-border);
  font: inherit;
  font-size: 1rem;
  background: var(--color-bg);
  color: var(--color-text);
}

.form-field select,
.form-field input[type="text"],
.form-field input[type="url"] { height: 44px; }
.form-field textarea { resize: vertical; min-height: 110px; }

/* "New idea" description field reuses .chat-composer-input (same rounded
   auto-grow box as Messages/Ideas comments), so it needs to win over the
   plain .form-field textarea rule above - a higher-specificity descendant
   selector rather than !important. Taller than the inline chat composer
   since a full idea write-up is longer than a quick message. */
.form-field .chat-composer-input {
  min-height: 90px;
  max-height: 260px;
  resize: none;
}
.form-field input[type="file"] { padding: 8px; }

/* The "Choose file" control is a separate UA-rendered sub-element, not
   covered by styling the input itself above - both the standard property
   and the older WebKit-prefixed one need setting for consistent coverage. */
.form-field input[type="file"]::file-selector-button,
.form-field input[type="file"]::-webkit-file-upload-button {
  padding: 8px 18px;
  margin-right: 12px;
  border: none;
  border-radius: 999px;
  background: var(--color-accent);
  color: var(--color-accent-contrast);
  font: inherit;
  font-weight: 600;
  font-size: 0.9rem;
  cursor: pointer;
}

.form-field input[type="file"]::file-selector-button:hover,
.form-field input[type="file"]::-webkit-file-upload-button:hover {
  opacity: 0.9;
}

.form-field select:focus,
.form-field textarea:focus,
.form-field input[type="text"]:focus,
.form-field input[type="url"]:focus,
.form-field input[type="file"]:focus {
  outline: 2px solid var(--color-accent);
  outline-offset: 1px;
}

/* Used on both <button> (no underline concern) and <a> (Log out, Back,
   "Open {FileType}", etc.) - text-decoration: none belongs here, not
   repeated per call site, so every link styled as this button is
   unaffected by the browser's default anchor underline. */
.btn-primary {
  display: inline-block;
  padding: 12px 28px;
  border-radius: 999px;
  border: none;
  background: var(--color-accent);
  color: var(--color-accent-contrast);
  font-weight: 600;
  font-size: 1rem;
  text-decoration: none;
  cursor: pointer;
}

.btn-primary:hover { opacity: 0.9; }

@media (min-width: 600px) {
  .chat-shell {
    display: grid;
    grid-template-columns: 1fr 300px;
    gap: 16px;
    align-items: start;
  }
  .chat-info { display: block; margin-top: 0; }

  /* Same independent-scroll reasoning as .pane-cascade (see its comment):
     .chat-thread only had min-height before, no cap, so it grew to fit
     every message and the whole page scrolled with it - dragging the
     sticky header/sidebar cards along and sliding the thread's rounded
     top edge underneath the header. Capping height here lets
     .chat-messages' own flex:1/overflow-y:auto (already set) actually
     engage, so only the message list scrolls and the composer stays
     pinned at the bottom. */
  .chat-thread,
  .chat-info {
    max-height: calc(100vh - var(--header-height) - 48px);
    overflow-y: auto;
  }
}

/* ---- Photos: a filter bar, a collapsible upload form, and a tile grid.
   Single flat page - no pane-cascade, see RenderPhotosPage. ---- */

.photo-filter-row {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 10px;
  margin-bottom: 16px;
}

.photo-filter-row label {
  display: flex;
  flex-direction: column;
  font-size: 0.75rem;
  color: var(--color-text-muted);
  gap: 4px;
}

.photo-filter-row select,
.photo-filter-row input[type="text"],
.photo-filter-row input[type="date"] {
  padding: 8px 10px;
  border-radius: 8px;
  border: 1px solid var(--color-border);
  font: inherit;
  background: var(--color-surface);
  color: var(--color-text);
  height: 38px;
}

.upload-details {
  margin-bottom: 20px;
}

.upload-details summary {
  cursor: pointer;
  font-weight: 600;
  color: var(--color-accent);
  padding: 4px 0;
}

.upload-details .review-form {
  margin-top: 12px;
  max-width: 420px;
}

.photo-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: 14px;
}

.photo-card {
  display: block;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: 10px;
  overflow: hidden;
  text-decoration: none;
  color: var(--color-text);
}

.photo-thumb {
  width: 100%;
  height: 140px;
  object-fit: cover;
  display: block;
  background: var(--color-bg);
}

.photo-caption {
  padding: 8px 10px 2px;
  font-size: 0.9rem;
  font-weight: 600;
}

.photo-meta {
  padding: 0 10px 10px;
  font-size: 0.75rem;
  color: var(--color-text-muted);
}

/* ---- Documents - 2-column layout (list-pane categories, detail-pane a
   thumbnail grid), same card shape as .photo-grid/.photo-card above by
   design - a document and a photo are both "a file with a thumbnail",
   just with a badge instead of a real image for non-image file types. ---- */

.doc-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: 14px;
}

.doc-card {
  display: block;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: 10px;
  overflow: hidden;
  text-decoration: none;
  color: var(--color-text);
}

.doc-thumb {
  width: 100%;
  height: 140px;
  object-fit: cover;
  display: block;
  background: var(--color-bg);
}

.doc-thumb-file {
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--color-text-muted);
  font-weight: 700;
  font-size: 0.85rem;
  letter-spacing: 0.04em;
}

/* 3D model badge (uploaded .glb or an external model link alike, see
   ClassifyDocumentKind) - the pale-green pane tint instead of the plain
   grey extension badge, so a model reads as distinct from an ordinary
   file at a glance in the grid. */
.doc-thumb-model {
  background: var(--color-pane-detail);
  color: var(--color-accent);
}

.doc-caption {
  padding: 8px 10px 2px;
  font-size: 0.9rem;
  font-weight: 600;
  overflow-wrap: break-word;
}

.doc-meta {
  padding: 0 10px 10px;
  font-size: 0.75rem;
  color: var(--color-text-muted);
}

/* Category accordion in the list-pane - the category name/count stays the
   real selection link (data-cascade-target, loads the grid on the right);
   the native <summary> disclosure triangle expands/collapses the nested
   document-name list independently of that link, so browsing names never
   navigates away from whatever grid is currently showing. */

.doc-category-item {
  width: 100%;
}

/* .list-pane li:last-child > .list-row's own margin-bottom:0 (see that
   rule's comment) only matches a .list-row that's a direct child of the
   <li> - ours sits inside <details><summary>, one level deeper, so it
   needs its own version of the same "no trailing gap on the last card"
   fix. */
.list-pane .doc-category-list > li:last-child .list-row {
  margin-bottom: 0;
}

.doc-category-item summary {
  list-style-position: outside;
  cursor: pointer;
}

.doc-name-list {
  margin: 0;
  padding: 2px 0 8px 30px;
  list-style: none;
}

.doc-name-list li {
  padding: 4px 0;
}

.doc-name-list a {
  font-size: 0.85rem;
  color: var(--color-text-muted);
  text-decoration: none;
}

.doc-name-list a:hover {
  color: var(--color-accent);
  text-decoration: underline;
}

/* ---- Login / account - no app shell/sidebar, just a centered card
   (login.html), unlike every other full page in this app. ---- */

.login-body {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
}

.login-card {
  width: 100%;
  max-width: 380px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: 12px;
  padding: 28px;
}

.login-card h1 {
  font-size: 1.3rem;
  margin: 0 0 20px;
}

.login-card .review-form {
  max-width: none;
  padding: 0;
  border: none;
}

/* ---- Project Manager (Architect-only header menu) - a plain <details>
   disclosure styled to look like the header's other icon buttons, not a
   new JS interaction pattern (same widget as the Photos/Documents upload
   forms use). ---- */

.pm-menu {
  position: relative;
}

.pm-menu summary.icon-button {
  cursor: pointer;
  list-style: none;
}

.pm-menu summary.icon-button::-webkit-details-marker {
  display: none;
}

.pm-menu[open] summary.icon-button {
  border-color: var(--color-accent);
  color: var(--color-accent);
}

.pm-menu-dropdown {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  z-index: 20;
  display: flex;
  flex-direction: column;
  min-width: 200px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: 10px;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
  overflow: hidden;
}

.pm-menu-dropdown a {
  padding: 12px 16px;
  color: var(--color-text);
  text-decoration: none;
  font-size: 0.9rem;
}

.pm-menu-dropdown a:hover {
  background: var(--color-bg);
}

.pm-menu-dropdown a + a {
  border-top: 1px solid var(--color-border);
}

/* ---- Stage/Task builder (Project Manager > Create New / stages) ---- */

.builder-stage-list {
  list-style: none;
  margin: 0 0 20px;
  padding: 0;
}

.builder-stage {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: 10px;
  padding: 14px 16px;
  margin-bottom: 12px;
}

.builder-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 6px 0;
}

.builder-row-title {
  font-weight: 600;
}

.builder-task-list {
  list-style: none;
  margin: 4px 0;
  padding: 0;
}

.builder-task-list .builder-row {
  padding-left: 16px;
  border-top: 1px solid var(--color-border);
}

.builder-task-list .builder-row-title {
  font-weight: normal;
}

.builder-row-actions {
  display: flex;
  gap: 2px;
  flex-shrink: 0;
}

.builder-row-actions form {
  display: inline;
}

.link-button {
  border: none;
  background: none;
  color: var(--color-text-muted);
  cursor: pointer;
  font-size: 0.95rem;
  padding: 4px 7px;
  border-radius: 6px;
}

.link-button:hover {
  color: var(--color-accent);
  background: var(--color-bg);
}

.inline-add-form {
  display: flex;
  gap: 8px;
  margin: 10px 0 20px;
  align-items: center;
  flex-wrap: wrap;
}

.inline-add-form input,
.inline-add-form select {
  flex: 1;
  min-width: 160px;
  padding: 8px 10px;
  border-radius: 8px;
  border: 1px solid var(--color-border);
  font: inherit;
  background: var(--color-bg);
  color: var(--color-text);
}

/* ---- Blueprint background - replaced the old dark green/amber animated
   "gradient mesh" (Mike: "the dark green doesn't work") with a pale ground,
   a fine architect's grid, and a collage of the same floor plan drawing
   (blueprint-plan.svg, baked in at 13% opacity - see that file's own
   comment) repeated at different sizes/rotations so it covers most of the
   viewport instead of sitting in one corner. Approved direction after a
   mockup review - grid from one candidate, the detailed plan from another,
   same --color-accent green throughout, no new hues. Apply "blueprint-bg"
   to any element that should get the grid (currently just login.html's
   <body>, via RespondCardPage's shared shell) - the plan collage itself is
   the separate .blueprint-collage markup below it, since CSS background-image
   layers can't be rotated individually. ---- */

.blueprint-bg {
  background-color: #f5f7f4;
  background-image:
    linear-gradient(rgba(31, 107, 63, 0.07) 1px, transparent 1px),
    linear-gradient(90deg, rgba(31, 107, 63, 0.07) 1px, transparent 1px);
  background-size: 22px 22px;
}

/* Fixed (not absolute) so it covers the viewport regardless of where it
   sits in .login-body's flex-centered flow, and z-index: -1 relative to
   the login-body's own stacking context keeps it behind the card without
   needing position:relative on login-body itself. pointer-events: none so
   it never intercepts clicks meant for the card. */
.blueprint-collage {
  position: fixed;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  pointer-events: none;
}

/* Each of the 4 gets its own center, arranged in a 200px square around
   the viewport middle (where the login card sits) rather than all 4
   sharing one exact point - a shared center buried most of each drawing
   under the others right where the card covers it; spreading the centers
   out means each drawing still overlaps its neighbours (so it reads as
   one radiating collage, not four separate corners) while showing much
   more of its own linework beyond just the overlap zone. */
.blueprint-collage .bp {
  position: absolute;
  display: block;
  height: auto;
}

.bp1 { width: 620px; top: calc(50% - 200px); left: calc(50% - 200px); transform: translate(-50%, -50%) rotate(76deg); }
.bp2 { width: 560px; top: calc(50% - 200px); left: calc(50% + 200px); transform: translate(-50%, -50%) rotate(113deg); opacity: 0.85; }
.bp3 { width: 640px; top: calc(50% + 200px); left: calc(50% - 200px); transform: translate(-50%, -50%) rotate(-52deg); opacity: 0.75; }
.bp4 { width: 580px; top: calc(50% + 200px); left: calc(50% + 200px); transform: translate(-50%, -50%) rotate(61deg);  opacity: 0.8; }

/* ---- Home "Let's Explore" collage - hidden entirely (no markup at all)
   unless there's at least one image in the "Plans and Drawings" document
   category, see BuildHomeCollageHtml. Background matches the pale green
   used for most card backgrounds elsewhere (--color-pane-detail, the
   pane-cascade detail-pane/context-panel color) rather than a bespoke
   look, so it reads as "part of the app" rather than a one-off banner. ---- */

.home-collage {
  position: relative;
  margin-bottom: 20px;
  border-radius: 12px;
  padding: 10px;
  background: var(--color-pane-detail);
}

.collage-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 10px;
}

/* .collage-image is the clickable <a> wrapper now (opens the Viewer Page) -
   object-fit only applies to replaced elements (img/video), so it lives on
   the nested <img>, not the anchor itself. */
.collage-image {
  width: 100%;
  height: 220px;
  display: block;
  border-radius: 6px;
  overflow: hidden;
}

.collage-image img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* Mobile-first: only the 1st image shows below 600px (screen's too narrow
   for a multi-image grid to read as anything but cramped); the full set
   (up to 3, see BuildHomeCollageHtml) comes back at desktop widths. */
.collage-image:nth-child(n+2) {
  display: none;
}

@media (min-width: 600px) {
  .collage-image:nth-child(n+2) {
    display: block;
  }
}

/* Same padding/weight/size as .btn-primary (Save, Upload document, Log in,
   etc.) - it was sized as its own one-off hero button before, which read
   as inconsistent next to every other action in the app. Keeps its own
   box-shadow since it sits on top of photos, not a plain form background,
   and needs to stay legible against busy image content. */
.collage-explore-button {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  padding: 12px 28px;
  border-radius: 999px;
  background: var(--color-accent);
  color: var(--color-accent-contrast);
  text-decoration: none;
  font-weight: 600;
  font-size: 1rem;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3);
}

.collage-explore-button:hover {
  opacity: 0.92;
}

/* ---- Viewer Page - the one branded page every document/photo/attachment
   opens into (RenderDocumentViewerPage/RenderPhotoViewerPage). .viewer-body
   sits first, right below the sticky header, filling the available content
   area using the same calc(100vh - header - 48px) formula as every other
   "fill the rest of the screen" container in this stylesheet (pane-cascade
   panes, chat-thread, content-scroll) - minus .viewer-footer's own height
   (~90px) since that now follows the body instead of preceding it.
   .viewer-footer sticks to the bottom of .content-scroll the same way
   .app-header sticks to its top - file details + Back stay reachable
   without scrolling past a tall viewer. On mobile everything just takes its
   natural height/order, same content-scroll fallback as everywhere else. ---- */

.viewer-body {
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--color-pane-detail);
  border: 1px solid var(--color-border);
  border-radius: 10px;
  overflow: hidden;
  margin-bottom: 16px;
  min-height: 320px;
}

@media (min-width: 600px) {
  .viewer-body {
    height: calc(100vh - var(--header-height) - 48px - 90px);
  }
}

.viewer-image {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  display: block;
}

.viewer-frame {
  width: 100%;
  height: 100%;
  min-height: 320px;
  border: 0;
  display: block;
}

.viewer-model {
  width: 100%;
  height: 100%;
  min-height: 320px;
  display: block;
}

.viewer-office-fallback {
  padding: 48px 24px;
  text-align: center;
}

.viewer-footer {
  position: sticky;
  bottom: 0;
  z-index: 5;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: 10px;
  padding: 12px 16px;
}

.viewer-footer-info h2 {
  margin: 0 0 2px;
  font-size: 1rem;
}

.viewer-meta {
  color: var(--color-text-muted);
  font-size: 0.85rem;
  margin: 0;
}

.viewer-footer-actions {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-shrink: 0;
}

/* Kept in the markup, not deleted - Mike isn't sure yet whether to allow
   direct downloads of the original file, so it's hidden rather than
   removed until that's decided. */
.viewer-download-link {
  display: none;
}
