/* =============================================================================
   PROJECT EDITOR
   =============================================================================
   The staff-side edit screen for one project.

   WHY THIS FILE EXISTS
   --------------------
   The screen used to be a single Bootstrap card holding one uninterrupted
   column: city, state, visibility, trades, a nested photo card, three dates,
   two contact selects, the file list, the uploader, a save button, a delete
   card and the invite email template -- roughly four viewports of scrolling
   with <hr> rules as the only structure. Everything was equally prominent, so
   nothing was, and the Save button sat at a point on the page you had to go
   looking for.

   It is now one form split into sections, with a persistent rail to move
   between them and a save bar that stays in view. The form element is still
   ONE form: every section posts together, so a coordinator changing a date and
   a contact saves once. Sections are shown and hidden, never detached, which
   is what keeps that true.

   Two sections sit outside that form -- the invite email (which contains a
   regenerate-token form of its own) and Delete (likewise). Nested forms are
   not valid HTML, so those are siblings that the rail switches to in the same
   way.

   Every colour here is a token from the theme's design system, so both themes
   work with no second code path. Nothing uses a Bootstrap colour utility.
   ========================================================================== */

.am-editor {
  display: grid;
  gap: var(--am-gap-lg);

  /* Set from JS to the real height of the sticky site header, so the rail and
     the save bar park against it rather than under it. The fallback is a
     sensible guess for a first paint before the script runs. */
  --am-editor-top: 5rem;
}


/* --- Head ------------------------------------------------------------------
   The project's identity plus the two things staff reach for without editing
   anything: the live page, and the deadline in their own calendar. */

.am-editor-head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--am-gap);
  padding-bottom: var(--am-gap);
  border-bottom: 1px solid var(--am-border);
}

.am-editor-head-main {
  min-width: min(100%, 20rem);
  flex: 1 1 26rem;
}

/* Several components below are <p> elements chosen for their semantics -- a
   status line, a readout, a warning are all sentences. Bootstrap gives every
   paragraph a bottom margin, and these all sit in grids that own their own
   spacing, so the margin is cleared once here rather than fought per component
   with a utility class in the markup. */
.am-editor .am-eyebrow,
.am-editor-status,
.am-savebar-status,
.am-contactcard,
.am-readout {
  margin: 0;
}

.am-editor-title {
  margin: .15rem 0 0;
  font-size: var(--am-text-2xl);
  font-weight: 750;
}

/* Location and deadline, the two facts that tell you which project this is
   when three tabs are open. */
.am-editor-sub {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .4rem .6rem;
  margin: .45rem 0 0;
  font-size: var(--am-text-sm);
  color: var(--am-text-muted);
}

.am-editor-sub .am-dotsep {
  color: var(--am-border-strong);
}

/* Narrow enough that location and deadline are on separate lines anyway, and the
   separator between them is then a bullet dangling at the end of the first. */
@media (max-width: 30rem) {
  .am-editor-sub .am-dotsep { display: none; }

  /* Full-width Save. At this width the bar has stacked, and a button sized to
     its label sitting alone on a line reads as unimportant -- which is the one
     thing the primary action on the screen must not read as. */
  .am-savebar-actions {
    width: 100%;
  }

  .am-savebar-actions .btn[type="submit"] {
    flex: 1;
  }
}

.am-editor-head-side {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--am-gap-sm);
}

/* Saved / failed feedback. Dismissible because it is stale the moment the next
   edit begins, and it sits above the panels rather than at the top of the
   document so it is next to the thing it is talking about. */
.am-editor-notice {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--am-gap);
  margin: 0;
}

.am-editor-notice > div:first-child {
  min-width: 0;
}

.am-notice-dismiss {
  flex: none;
  border: 0;
  background: transparent;
  color: inherit;
  opacity: .7;
  padding: 0 .25rem;
  font-size: 1.1rem;
  line-height: 1;
  cursor: pointer;
}

.am-notice-dismiss:hover {
  opacity: 1;
}


/* --- Body: rail + panels --------------------------------------------------- */

.am-editor-body {
  display: grid;
  grid-template-columns: 15.5rem minmax(0, 1fr);
  align-items: start;
  gap: var(--am-gap-lg);
}

.am-editor-rail {
  position: sticky;
  top: calc(var(--am-editor-top) + var(--am-gap-sm));
  display: grid;
  gap: var(--am-gap-sm);
  /* Its own scroll if the section list ever outgrows a short viewport, rather
     than pushing the page. */
  max-height: calc(100dvh - var(--am-editor-top) - var(--am-gap-lg));
  overflow-y: auto;
  overscroll-behavior: contain;
}

.am-editor-panels {
  min-width: 0;   /* grid children default to min-content; long filenames win */
  display: grid;
  gap: var(--am-gap-lg);
}


/* --- The section rail -----------------------------------------------------
   A list of the work, not a set of tabs pretending the sections are peers of
   the page. Each item carries its own state: how many files are attached, or
   that something required is still empty. That is the whole reason it beats
   scrolling -- you can see what is left without visiting every section. */

.am-editor-nav {
  display: grid;
  gap: .2rem;
  padding: .4rem;
  background: var(--am-surface);
  border: 1px solid var(--am-border);
  border-radius: var(--am-radius);
}

.am-navitem {
  display: grid;
  grid-template-columns: 1.4rem minmax(0, 1fr) auto;
  align-items: center;
  gap: .6rem;
  width: 100%;
  padding: .55rem .6rem;
  border: 0;
  border-radius: var(--am-radius-sm);
  background: transparent;
  color: var(--am-text-muted);
  font: inherit;
  font-size: var(--am-text-sm);
  font-weight: 550;
  text-align: left;
  cursor: pointer;
  transition: background-color var(--am-speed) var(--am-ease),
              color var(--am-speed) var(--am-ease);
}

.am-navitem:hover {
  background: var(--am-surface-sunk);
  color: var(--am-text);
}

/* The current section. A left edge plus a weight change, not a colour fill:
   the rail sits beside a form full of controls, and a solid block of accent
   next to them competes with the field that actually has focus. */
.am-navitem[aria-selected="true"] {
  background: color-mix(in oklab, var(--am-accent) 10%, var(--am-surface));
  color: var(--am-text);
  font-weight: 650;
  box-shadow: inset 2px 0 0 var(--am-accent);
}

.am-navitem-ico {
  display: grid;
  place-items: center;
  color: var(--am-text-subtle);
}

.am-navitem[aria-selected="true"] .am-navitem-ico {
  color: var(--am-accent-ink);
}

.am-navitem-ico svg {
  width: 1.05rem;
  height: 1.05rem;
}

.am-navitem-label {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* A count, or a short state word. Tabular so a two-digit file count does not
   shift the row. */
.am-navitem-meta {
  font-size: var(--am-text-xs);
  font-weight: 600;
  color: var(--am-text-subtle);
  font-variant-numeric: tabular-nums;
}

/* "Something in here is not filled in." Amber, not red: nothing has failed
   yet, the form simply is not finished. Red on this screen means the deadline
   or the delete panel.

   --am-warn-ink and the other status tokens used to be raw hex values, written
   out here and declared twice for browsers without light-dark(). They are one
   token now and the pair lives in style.css, which is what got them measured:
   the ready badge below had been shipping at 4.15:1 on its own green tint, and
   the contrast checker could not see it because it measures tokens. */
.am-navitem-meta.is-todo {
  color: var(--am-warn-ink);
}

.am-navitem--danger:hover {
  color: var(--am-danger-ink);
}

.am-navitem--danger .am-navitem-ico {
  color: color-mix(in oklab, var(--am-danger) 70%, var(--am-text-subtle));
}


/* --- Rail footer: what is left --------------------------------------------
   One line, and it either says the form is complete or names the count. A
   progress bar was tried here and read as decoration: with four required
   fields the bar is either full or nearly full, which tells nobody anything. */

.am-editor-status {
  display: flex;
  align-items: flex-start;
  gap: .5rem;
  padding: .7rem .8rem;
  background: var(--am-surface-sunk);
  border: 1px solid var(--am-border);
  border-radius: var(--am-radius);
  font-size: var(--am-text-xs);
  line-height: 1.5;
  color: var(--am-text-muted);
}

/* An inline SVG carries a viewBox and no intrinsic size, and the theme's
   `img, svg { height: auto }` would let it grow to whatever box it lands in.
   Every icon on this screen is sized by the component that holds it. */
.am-editor-status svg,
.am-softwarn svg,
.am-removenote svg {
  flex: none;
  width: 1rem;
  height: 1rem;
  margin-top: .1rem;
}

/* The state icon. Both are rendered and the class picks one, so the glyph can
   never contradict the sentence beside it -- a tick above "2 required fields are
   still empty" is worse than no icon at all. */
.am-editor-status > svg {
  display: none;
}

.am-editor-status.is-ready > .am-status-ico--ready,
.am-editor-status.is-todo > .am-status-ico--todo {
  display: block;
}

.am-editor-status.is-ready {
  color: var(--am-success-ink);
  border-color: color-mix(in oklab, var(--am-success) 30%, transparent);
  background: color-mix(in oklab, var(--am-success) 8%, var(--am-surface-sunk));
}

.am-editor-status.is-todo {
  color: var(--am-warn-ink);
  border-color: color-mix(in oklab, var(--am-amber) 32%, transparent);
  background: color-mix(in oklab, var(--am-amber) 8%, var(--am-surface-sunk));
}


/* --- Panels ---------------------------------------------------------------
   .am-panel and .am-panel-head come from the theme; only the section-switching
   behaviour and the internal rhythm are added here. */

.am-editor-panel {
  display: grid;
  gap: var(--am-gap);
}

/* `hidden` alone loses to the display above, and a section that is merely
   transparent still takes tab stops. */
.am-editor-panel[hidden],
.am-editor-form[hidden] {
  display: none;
}

/* --- A section built out of panels ----------------------------------------
   Mail is not a form. Its body is the Correspondence and Offers panels, the
   same two functions the invitation record calls, and on that screen they are
   the top-level cards on the page background -- so they carry a card each.

   Dropped inside a section that is already a card, that is a box in a box, and
   the second frame buys nothing: the section heading above it has already said
   what the reader is looking at. The section keeps its frame and its children
   lose theirs. The first child loses its heading as well (the editor asks the
   panel for none -- 'head' => false), since "Correspondence" straight under
   "Mail" was two titles on one list; the offers panel keeps its own, because
   it is the second list and the boundary has to be drawn somewhere.

   Not written as `.am-editor-panel > .am-panel`. Delete is a panel with a
   danger modifier and would be caught by a rule that broad the day anything is
   nested inside it.

   And the margin goes with the frame: .am-inbox carries a bottom margin for
   the screen where it is one card among several, which inside a grid that
   already spaces its children would be a gap of two. */
.am-editor-panel--nested > .am-panel {
  padding: 0;
  margin: 0;
  background: none;
  border: 0;
  border-radius: 0;
}

/* Grid, not flex.
   As flex with `flex-basis: 100%` on the hint this looked right in theory and
   was wrong on screen: a flex item still SHRINKS below its basis by default, so
   the hint sat in the right-hand half of the row beside the heading instead of
   wrapping under it. Two columns with an explicit span is not negotiable in the
   same way. */
.am-editor-panel > .am-panel-head {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: .3rem var(--am-gap-sm);
}

.am-panel-hint {
  grid-column: 1 / -1;
  max-width: 72ch;
  margin: .15rem 0 0;
  font-size: var(--am-text-sm);
  color: var(--am-text-muted);
}

/* A sub-group inside a panel -- "Existing files", "Upload new". Quieter than a
   panel head, because it is not a section of the page. */
.am-subhead {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--am-gap-sm);
  margin: 0;
  font-size: var(--am-text-xs);
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--am-text-subtle);
}

.am-editor-form {
  display: grid;
  gap: var(--am-gap-lg);
}

/* Every caption on this screen is one shape.
   The form previously mixed two: `form-label fw-bold` on City and Visibility
   (sentence case, bold, full size) and .am-field on the three dates (uppercase,
   small, muted), a few hundred pixels apart, which is most of why it read as
   several forms stitched together. The theme styles .am-field's captions
   already; this adds the one case it does not cover -- a <legend>, which is
   what names a group of checkboxes or radios. */
.am-editor .am-fieldset > .form-label {
  display: block;
  font-size: var(--am-text-xs);
  font-weight: 600;
  letter-spacing: .03em;
  text-transform: uppercase;
  color: var(--am-text-subtle);
  margin-bottom: .35rem;
}

/* One column grid for the whole panel, not two that disagree.

   The fields and the choice cards under them are separate grids, and each was
   left to work out its own column count from a minimum track width -- the
   theme's .am-formgrid from 16rem, .am-choices from 17rem. On a panel around
   50rem wide that arithmetic comes out at THREE tracks for the fields and TWO
   for the cards, so City stopped about 140px short of the card beneath it and
   the right-hand edges of the section formed a staircase.

   The empty third track is not something auto-fit can collapse away, either:
   it collapses tracks that hold no items, and the full-width Project name
   spans `1 / -1` across all of them.

   Both rows carry exactly two things -- city and state, manager and
   coordinator, public and private -- so the panel is two equal columns and
   says so. minmax(0, 1fr) rather than a minimum track width because a floor is
   what made this negotiable in the first place; these tracks share whatever
   the panel has and never overflow it.

   .am-choices keeps its own auto-fit track sizing, which already resolves to
   two equal columns at every width: the tracks beyond the second hold nothing
   and collapse. It agrees with the two above by construction rather than by a
   second number kept in step by hand.

   Its GAP has to be said, though. It was the small step where the fields use
   the full one, so the two rows came out 393px and 396px wide and met at a
   seam three pixels out of true -- the outer edges of the section flush, the
   join down the middle not. Small enough to look like a rendering fault rather
   than a decision, which is the worst size for it to be. */
.am-editor .am-formgrid {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

.am-editor .am-choices {
  gap: var(--am-gap);
}

/* Scope of work, at the height it is actually written at.

   The theme's 7.5rem floor is for a textarea that is the point of its page.
   This one is three lines about a job, sitting above the two things somebody
   opens Overview to check -- who can see the project, and the link they are
   about to send -- and 120px of empty box was pushing them under the fold.
   It still drags taller by the handle, and the stored text is untouched
   either way: nothing here caps what can be typed. */
.am-editor .am-textarea--brief {
  min-height: 4.75rem;
}

/* And they come apart at one width, together.

   44rem is where the photo frame beside its own fields already stacks, further
   down. Left to themselves these two would have gone at different points --
   the fields here, the cards at their own 17rem floor some 8rem later -- so a
   window dragged narrower would have rearranged the same section twice, once
   into a shape where stacked fields sat above a side-by-side pair. Whatever
   the width, the section is one shape or the other. */
@media (max-width: 44rem) {
  .am-editor .am-formgrid,
  .am-editor .am-choices {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* Bootstrap's reboot carries [hidden]{display:none!important}, so the attribute
   wins over every display above on its own. These are here for the case where
   this sheet is used without Bootstrap, and to keep the intent readable next to
   the components that rely on it. */
.am-readout[hidden],
.am-softwarn[hidden],
.am-contactcard[hidden],
.am-tradebox-empty[hidden] {
  display: none;
}


/* --- The save bar --------------------------------------------------------
   Parked at the bottom of the viewport for as long as the form is open. The
   old Save button sat after the uploader, four screens down, and the only way
   to know whether an edit had been kept was to remember whether you had
   scrolled that far. It states the state, then offers the action. */

.am-savebar {
  position: sticky;
  bottom: 0;
  z-index: 5;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--am-gap);
  margin-top: calc(var(--am-gap-sm) * -1);
  padding: .8rem clamp(.85rem, .6rem + .7vw, 1.25rem);
  background: var(--am-surface);
  border: 1px solid var(--am-border);
  border-radius: var(--am-radius);
  box-shadow: var(--am-shadow);
}

.am-savebar-status {
  display: flex;
  align-items: center;
  gap: .5rem;
  min-width: 0;
  font-size: var(--am-text-sm);
  color: var(--am-text-muted);
}

.am-savebar-actions {
  display: flex;
  align-items: center;
  gap: var(--am-gap-sm);
}

/* The dirty indicator. A dot rather than a word alone, so the state is visible
   from the corner of the eye while typing in a field halfway up the panel. */
.am-savedot {
  flex: none;
  width: .5rem;
  height: .5rem;
  border-radius: 50%;
  background: var(--am-border-strong);
  transition: background-color var(--am-speed) var(--am-ease);
}

.am-savebar.is-dirty .am-savedot {
  background: var(--am-amber);
}

.am-savebar.is-dirty .am-savebar-status {
  color: var(--am-text);
  font-weight: 550;
}

/* A save that was refused. The reason is in the text beside this dot -- the
   browser's own validation message, put here because its bubble cannot appear
   over a field that flatpickr has hidden behind a substitute. */
.am-savebar.is-invalid {
  border-color: color-mix(in oklab, var(--am-danger) 45%, var(--am-border));
}

.am-savebar.is-invalid .am-savedot {
  background: var(--am-danger);
}

.am-savebar.is-invalid .am-savebar-status {
  color: var(--am-danger-ink);
  font-weight: 600;
}

/* Discard is only meaningful once there is something to discard. */
.am-savebar:not(.is-dirty) [data-am-reset] {
  display: none;
}


/* --- Choice cards --------------------------------------------------------
   Visibility was a <select> with two options whose consequences are entirely
   different: one puts the project on a public calendar, the other hands out a
   secret link. A closed dropdown shows one of those and explains neither. */

.am-choices {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr));
  gap: var(--am-gap-sm);
}

.am-choice {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: start;
  gap: .7rem;
  margin: 0;
  padding: .85rem 1rem;
  background: var(--am-surface-sunk);
  border: 1px solid var(--am-border);
  border-radius: var(--am-radius);
  cursor: pointer;
  transition: border-color var(--am-speed) var(--am-ease),
              background-color var(--am-speed) var(--am-ease);
}

.am-choice:hover {
  border-color: var(--am-border-strong);
}

.am-choice > input {
  margin: .2rem 0 0;
  flex: none;
}

/* :has() rather than a class toggled from script, so the selected state is
   correct before any JS runs and stays correct if it never does. */
.am-choice:has(> input:checked) {
  border-color: var(--am-accent);
  background: color-mix(in oklab, var(--am-accent) 8%, var(--am-surface-sunk));
}

.am-choice:has(> input:focus-visible) {
  box-shadow: var(--am-ring);
}

.am-choice-title {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .45rem;
  font-size: var(--am-text-sm);
  font-weight: 650;
  color: var(--am-text);
}

.am-choice-desc {
  display: block;
  margin-top: .2rem;
  font-size: var(--am-text-xs);
  line-height: 1.55;
  color: var(--am-text-muted);
}


/* --- A URL to hand out ---------------------------------------------------
   The link a contractor receives. It was previously only reachable by copying
   the whole invite email and reading the href out of it, which is why people
   were sending the browser's own address bar URL instead -- and that one
   carries no access token, so a private invite led to a 404. */

.am-linkout {
  display: grid;
  gap: .4rem;
  padding: .8rem 1rem;
  background: var(--am-surface-sunk);
  border: 1px solid var(--am-border);
  border-radius: var(--am-radius);
}

.am-linkout-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: .5rem;
}

.am-linkout-label {
  font-size: var(--am-text-xs);
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--am-text-subtle);
}

.am-linkout-row {
  display: flex;
  flex-wrap: wrap;
  gap: .4rem;
}

.am-linkout-row input {
  flex: 1 1 18rem;
  min-width: 0;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: var(--am-text-xs);
}

/* The theme's touch floor, restated because this selector outranks it.

   --am-text-xs is about 11px on a phone, which is the deepest under iOS
   Safari's 16px zoom threshold anything on the site gets. The field holds an
   invite URL that staff are meant to read before sending it, so the size is
   worth having on a phone regardless of the zoom. See the note beside the
   floor in the theme stylesheet. */
@media (pointer: coarse) {
  .am-linkout-row input {
    font-size: max(1rem, var(--am-text-xs));
  }
}

.am-linkout-note {
  margin: 0;
  font-size: var(--am-text-xs);
  color: var(--am-text-muted);
}

/* Inside the visibility fieldset rather than under it.

   These were two sunken boxes in a column saying they were two questions.
   They are one: the radio decides which URL this field holds, the note under
   it is a sentence about the radio, and the pending warning is about a change
   to the radio that has not been saved. Folded into the group, the box of its
   own is what goes -- a panel inside a panel, and about 40px of padding and
   gap spent drawing a line between a choice and its consequence. */
.am-linkout--inset {
  /* .am-fieldset is a plain block, so the space between the cards and the
     field is a margin here rather than a grid gap. */
  margin-top: var(--am-gap-sm);
  padding: 0;
  background: none;
  border: 0;
  border-radius: 0;
}


/* --- Trade picker wrapper ------------------------------------------------
   The picker itself is shared markup (mu-plugins/americon-assets.php). What is
   added here is a filter and a count: the list runs to several dozen trades in
   a 14rem scroll box, so "is Electrical ticked" was a scrolling job. */

.am-tradebox {
  display: grid;
  gap: .5rem;
}

.am-tradebox-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--am-gap-sm);
}

.am-tradebox-head input[type="search"] {
  flex: 1 1 11rem;
  min-width: 0;
}

.am-tradebox-count {
  font-size: var(--am-text-xs);
  font-weight: 650;
  color: var(--am-text-muted);
  font-variant-numeric: tabular-nums;
}

/* A trade hidden by the filter, rather than removed: the checkbox stays in the
   form, so filtering can never silently drop a selection on save. */
.am-trade-option[hidden] {
  display: none;
}

/* Shown when the filter matches nothing, so an empty box does not read as "this
   project has no trades available". */
.am-tradebox-empty {
  margin: 0;
  font-size: var(--am-text-sm);
  color: var(--am-text-subtle);
}

/* Ticked trades are tinted so a selection is readable at a glance in a grid of
   forty labels, where a 16px checkbox is not. */
.am-editor .am-trade-option {
  padding: .2rem .4rem;
  border-radius: var(--am-radius-sm);
}

.am-editor .am-trade-option:has(input:checked) {
  background: color-mix(in oklab, var(--am-accent) 12%, transparent);
  font-weight: 600;
}


/* --- Schedule readout ---------------------------------------------------
   What the stored deadline actually means, in words, under the field that sets
   it. The picker shows "08-12-2026 2:00 PM" with no zone and no sense of how
   far away that is; this is the sentence a coordinator is checking. */

.am-daterow {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 14rem), 1fr));
  align-items: start;
  gap: var(--am-gap);
}

.am-readout {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .5rem;
  padding: .7rem .9rem;
  background: var(--am-surface-sunk);
  border: 1px solid var(--am-border);
  border-left: 3px solid var(--am-border-strong);
  border-radius: var(--am-radius-sm);
  font-size: var(--am-text-sm);
}

.am-readout--open   { border-left-color: var(--am-success); }
.am-readout--soon   { border-left-color: var(--am-amber); }
.am-readout--today  { border-left-color: var(--am-danger); }
.am-readout--past   { border-left-color: var(--am-text-muted); }

.am-readout-label {
  font-size: var(--am-text-xs);
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--am-text-subtle);
}

/* Shown only while an edit is pending, so the sentence above it is never
   quietly wrong about a value that has not been saved. */
.am-readout--pending {
  border-left-color: var(--am-accent);
  background: color-mix(in oklab, var(--am-accent) 7%, var(--am-surface-sunk));
}

/* A soft objection -- a completion date before the start date. Not a
   validation error: the dates are estimates and staff may know something the
   form does not, so this says so and gets out of the way. */
.am-softwarn {
  display: flex;
  align-items: flex-start;
  gap: .5rem;
  margin: 0;
  padding: .6rem .8rem;
  border-radius: var(--am-radius-sm);
  background: color-mix(in oklab, var(--am-amber) 12%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--am-amber) 30%, transparent);
  font-size: var(--am-text-xs);
  line-height: 1.55;
  color: var(--am-warn-ink);
}

/* The one that is not an aside.
   ----------------------------
   Most .am-softwarn on this screen annotate a field: worth knowing, not worth
   stopping for, and sized accordingly. The draft warning in the invite panel is
   different in kind -- it says the two controls directly under it do not work
   yet -- so it is the same colour at reading size, with an edge to catch the
   eye on the way past.

   Amber and not red, for the reason the draft bar gives: a draft is the normal
   state of a project somebody is still setting up, and a red panel over the
   ordinary case is the one that teaches people to skip the red panels. */
.am-softwarn--stop {
  padding: .7rem .9rem;
  border-left: 3px solid var(--am-amber);
  border-start-start-radius: 0;
  border-end-start-radius: 0;
  font-size: var(--am-text-sm);
  font-weight: 500;
}


/* --- Contacts summary --------------------------------------------------- */

.am-contactcard {
  display: grid;
  gap: .3rem;
  padding: .8rem 1rem;
  background: var(--am-surface-sunk);
  border: 1px solid var(--am-border);
  border-radius: var(--am-radius);
  font-size: var(--am-text-sm);
}

.am-contactcard-label {
  font-size: var(--am-text-xs);
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--am-text-subtle);
}

.am-contactcard strong {
  font-weight: 650;
}


/* --- Photo ---------------------------------------------------------------- */

.am-photo {
  display: grid;
  grid-template-columns: minmax(min(100%, 15rem), 22rem) minmax(0, 1fr);
  align-items: start;
  gap: var(--am-gap);
}

@media (max-width: 44rem) {
  .am-photo { grid-template-columns: 1fr; }
}

.am-photo-frame {
  position: relative;
  aspect-ratio: 16 / 10;
  overflow: hidden;
  background: var(--am-surface-sunk);
  border: 1px solid var(--am-border);
  border-radius: var(--am-radius);
}

.am-photo-frame img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* No photo yet. Hatched rather than blank so it reads as an empty slot and not
   as an image that failed to load. */
.am-photo-frame--empty {
  display: grid;
  place-items: center;
  gap: .35rem;
  align-content: center;
  padding: var(--am-gap);
  text-align: center;
  font-size: var(--am-text-xs);
  color: var(--am-text-subtle);
  background:
    repeating-linear-gradient(45deg,
      var(--am-surface-sunk) 0 7px,
      color-mix(in oklab, var(--am-border) 55%, transparent) 7px 14px);
}

.am-photo-frame--empty svg {
  width: 2rem;
  height: 2rem;
  opacity: .75;
}

/* The badge over a locally-chosen file, before it has been saved. */
.am-photo-pending {
  position: absolute;
  left: .5rem;
  top: .5rem;
  padding: .2rem .5rem;
  border-radius: var(--am-radius-pill);
  background: color-mix(in oklab, var(--am-accent) 88%, transparent);
  color: #fff;
  font-size: var(--am-text-xs);
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
}

.am-photo-side {
  display: grid;
  gap: var(--am-gap-sm);
  align-content: start;
}

/* The frame is also the drop target, so the answer to "where do I put this
   photo" is the place the photo will appear. */
.am-photo-drop {
  transition: border-color var(--am-speed) var(--am-ease),
              box-shadow var(--am-speed) var(--am-ease);
}

.am-photo-drop.dragover {
  border-color: var(--am-accent);
  box-shadow: 0 0 0 3px color-mix(in oklab, var(--am-accent) 22%, transparent);
}


/* --- Plan file rows -----------------------------------------------------
   Three things about one file: what it is, which revision, and whether it
   survives the save. The old row put a bare "Keep" checkbox on the right, on
   by default, whose only visible effect was that unticking it deleted the file
   -- with nothing on screen saying so until after the save. */

/* Filter + count + bulk restore, above the list. Appears only past a handful of
   files; on a three-file project it would be furniture. */
.am-filebar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--am-gap-sm);
}

.am-filebar input[type="search"] {
  flex: 1 1 14rem;
  min-width: 0;
}

.am-filebar-shown {
  font-size: var(--am-text-xs);
  font-weight: 650;
  color: var(--am-text-muted);
  font-variant-numeric: tabular-nums;
}

.am-planlist {
  display: grid;
  gap: .5rem;
  list-style: none;
  margin: 0;
  padding: 0;
}

/* Fifty drawings is a real project, and fifty rows is the whole screen again --
   the exact problem the sections exist to remove, rebuilt inside one of them.
   Past eight files the list gets its own scroll, capped at roughly six rows so
   the panel keeps its shape and the save bar stays reachable.

   Padding on the right leaves the scrollbar off the switches, and the inline
   padding is mirrored so rows do not sit flush against the track. */
.am-planlist--scroll {
  max-height: 26rem;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: .25rem;
  margin: -.25rem;
  scrollbar-gutter: stable;

  /* Say that it scrolls.
     Without this the list simply stops mid-row and reads as a rendering fault
     -- a row sliced through the middle with nothing to suggest more follows. A
     mask fades the last few pixels out, and it lifts once the list is scrolled
     to the end so the final row is not permanently dimmed.

     mask rather than a gradient overlay because the rows underneath are
     interactive: an ::after covering them would eat clicks on the last row's
     switch, and pointer-events:none on a gradient still leaves it painting over
     a focus ring. */
  -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 2.5rem), transparent 100%);
          mask-image: linear-gradient(to bottom, #000 calc(100% - 2.5rem), transparent 100%);
}

/* animation-timeline is progressive: browsers without scroll-driven animations
   simply keep the fade, which is the correct fallback -- the cue is still right,
   it just does not retract at the end of the list. */
@supports (animation-timeline: scroll()) {
  .am-planlist--scroll {
    animation: am-unfade both linear;
    animation-timeline: scroll(self block);
    animation-range: contain 85% contain 100%;
  }

  @keyframes am-unfade {
    to {
      -webkit-mask-image: linear-gradient(to bottom, #000 100%, #000 100%);
              mask-image: linear-gradient(to bottom, #000 100%, #000 100%);
    }
  }
}

/* A row hidden by the filter, not removed: plan_keep[] is an opt-in list, so a
   row detached from the form is a file deleted on save. */
.am-planrow[hidden] {
  display: none;
}

/* Tight on purpose. At fifty files the row height is the whole ergonomics of
   this panel: every 30px shaved is another file visible without scrolling. */
.am-planrow {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 9rem auto auto;
  align-items: center;
  gap: var(--am-gap-sm) var(--am-gap);
  padding: .5rem .85rem;
  background: var(--am-surface-sunk);
  border: 1px solid var(--am-border);
  border-radius: var(--am-radius-sm);
  transition: opacity var(--am-speed) var(--am-ease),
              border-color var(--am-speed) var(--am-ease);
}

@media (max-width: 52rem) {
  .am-planrow {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--am-gap-sm);
  }
}

.am-planrow-main {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  gap: .7rem;
  min-width: 0;
}

/* The extension, as a chip. Faster to scan down a column of ten files than the
   same three letters buried at the end of each name. */
/* .am-planrow-ext moved to the theme stylesheet.
   americon_plan_file_chip() renders it on the contractor's file list too, and
   this sheet only loads on the editor -- so the chip was styled on one of the
   two screens that draw it. */

.am-planrow-text {
  min-width: 0;
}

/* Filenames read as text, not as fifty blue underlined links.
   They ARE links and behave like them on hover and focus, but at this density
   default link styling turns the column into a wall of underline and pulls the
   eye away from the controls that actually change something. */
.am-planrow .am-file-name {
  color: var(--am-text);
  text-decoration: none;
}

.am-planrow .am-file-name:hover,
.am-planrow .am-file-name:focus-visible {
  color: var(--am-accent-ink);
  text-decoration: underline;
}

.am-planrow-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .25rem .5rem;
  margin-top: .1rem;
  font-size: var(--am-text-xs);
  color: var(--am-text-subtle);
}


.am-planrow-keep {
  display: flex;
  align-items: center;
  gap: .5rem;
  margin: 0;
  padding: 0;
  min-height: 0;
}

/* Bootstrap's .form-check floats its input and pulls it back with
   `margin-left: -1.5em` to sit in the padding it reserves. This row is a flex
   container with no such padding, so that negative margin dragged the switch
   left, on top of the revision field beside it -- and at narrow widths off the
   row entirely. Both are undone here rather than by dropping .form-switch,
   which is what draws the switch at all. */
.am-planrow-keep .form-check-input {
  float: none;
  margin: 0;
  flex: none;
}

.am-planrow-keep .form-check-label {
  font-size: var(--am-text-xs);
  font-weight: 650;
  letter-spacing: .03em;
  text-transform: uppercase;
  color: var(--am-text-muted);
  cursor: pointer;
}

/* Replace: a quiet outline button. It sits beside Keep because the two are
   the same kind of decision about the same file, and both belong at the end
   of the row where the eye lands after reading the name. */
.am-planrow-replace .btn {
  white-space: nowrap;
}

/* The row is mid-replacement: a file has been chosen and is uploading or
   uploaded, and this row leaves the list on save. Same visual language as
   is-removing, different colour, because it is the same fact -- this row is
   on its way out -- arriving by a different and non-destructive route. */
.am-planrow.is-replacing {
  border-color: color-mix(in oklab, var(--am-accent) 45%, var(--am-border));
  background: color-mix(in oklab, var(--am-accent) 6%, var(--am-surface-sunk));
}

.am-planrow.is-replacing .am-planrow-main {
  opacity: .7;
}

.am-planrow.is-replacing .am-planrow-keep,
.am-planrow.is-replacing .am-planrow-rev {
  visibility: hidden;
}

.am-planrow-replacing-note {
  grid-column: 1 / -1;
  margin: 0;
  font-size: var(--am-fs-sm);
  color: var(--am-accent-ink);
}

/* Earlier issues. Full width under the row, closed by default: on a set where
   nothing has been reissued this is absent entirely, and where it exists it
   must not cost the row any height until somebody asks. */
.am-planrow-history {
  grid-column: 1 / -1;
  margin: 0;
  font-size: var(--am-fs-sm);
}

.am-planrow-history > summary {
  cursor: pointer;
  color: var(--am-text-muted);
  padding: .15rem 0;
}

.am-planrow-history > summary:hover,
.am-planrow-history > summary:focus-visible {
  color: var(--am-text);
}

.am-planhistory {
  list-style: none;
  margin: .35rem 0 0;
  padding: 0 0 0 .25rem;
  display: grid;
  gap: .2rem;
}

.am-planhistory li {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: .5rem;
}

.am-planhistory-ver {
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  color: var(--am-text);
}

.am-planhistory-label,
.am-planhistory-at {
  color: var(--am-text-muted);
}

.am-planhistory-note {
  margin: .4rem 0 0;
  color: var(--am-text-muted);
}

/* Unticked: the row states its own fate. Struck through and dimmed, but still
   legible -- the point of showing it is that you can change your mind. */
.am-planrow.is-removing {
  border-color: color-mix(in oklab, var(--am-danger) 45%, var(--am-border));
  background: color-mix(in oklab, var(--am-danger) 6%, var(--am-surface-sunk));
}

.am-planrow.is-removing .am-planrow-main,
.am-planrow.is-removing .am-planrow-rev {
  opacity: .55;
}

.am-planrow.is-removing .am-file-name {
  text-decoration: line-through;
}

.am-planrow.is-removing .am-planrow-keep .form-check-label {
  color: var(--am-danger-ink);
}

/* One line, under the list, when at least one row is marked for removal. The
   count matters: "3 files will be removed" is the sentence that stops a
   mis-click from being discovered a week later. */
.am-removenote {
  display: flex;
  align-items: center;
  gap: .5rem;
  margin: 0;
  padding: .6rem .8rem;
  border-radius: var(--am-radius-sm);
  background: color-mix(in oklab, var(--am-danger) 10%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--am-danger) 30%, transparent);
  font-size: var(--am-text-xs);
  font-weight: 600;
  color: var(--am-danger-ink);
}

.am-removenote[hidden] {
  display: none;
}


/* --- Invite email panel -------------------------------------------------- */

/* The preview is CLAMPED, not collapsed. Copying works by selecting this
   element's contents, and a selection cannot be made inside display:none -- a
   <details> here would give you a Copy button that reports success and puts
   nothing on the clipboard. Clipped content is still rendered, so it copies.

   These selectors beat .am-email-preview on specificity (two classes to its
   one), which is how that sheet's 420px cap is reduced without touching it. */

.am-preview {
  display: grid;
  gap: var(--am-gap-sm);
  justify-items: start;
}

.am-preview > .am-email-preview {
  position: relative;
  width: 100%;
  max-height: 13rem;
  overflow: hidden;
}

/* The fade is white in both themes for the same reason the preview is: this is
   a picture of an email, and the email is white. */
.am-preview:not(.is-open) > .am-email-preview::after {
  content: "";
  position: absolute;
  inset: auto 0 0 0;
  height: 4rem;
  pointer-events: none;
  background: linear-gradient(to bottom, rgb(255 255 255 / 0), rgb(255 255 255 / .96));
}

.am-preview.is-open > .am-email-preview {
  max-height: 420px;
  overflow: auto;
}


/* --- Responsive: the rail becomes a strip -------------------------------
   Below this the two-column layout leaves the panels too narrow for a date
   field and its hint, so the rail lies down above the content. It stays
   sticky, because the whole point is being able to move sections without
   scrolling back up. */

@media (max-width: 63.99rem) {

  .am-editor-body {
    grid-template-columns: minmax(0, 1fr);
  }

  .am-editor-rail {
    position: sticky;
    top: var(--am-editor-top);
    z-index: 6;
    max-height: none;
    overflow: visible;
    gap: var(--am-gap-sm);
    padding-block: .4rem;
    background: var(--am-canvas);
  }

  .am-editor-nav {
    display: flex;
    gap: .25rem;
    overflow-x: auto;
    overscroll-behavior-inline: contain;
    scroll-snap-type: inline proximity;
    /* Hairline scrollbar; a full one under seven pills is most of the strip. */
    scrollbar-width: thin;
  }

  .am-navitem {
    width: auto;
    flex: none;
    grid-template-columns: auto auto auto;
    scroll-snap-align: start;
    white-space: nowrap;
  }

  .am-navitem[aria-selected="true"] {
    box-shadow: inset 0 -2px 0 var(--am-accent);
  }

  /* The rail's own summary line is redundant once the nav is a strip -- the
     per-section flags are still visible in it, and the save bar carries the
     state that matters. */
  .am-editor-status {
    display: none;
  }
}

/* Very small screens: the section labels alone would push the strip to three
   times the viewport width. Icons carry it, with the current section named.

   21rem, not the 26rem this started at. A 390px phone -- an iPhone 14/15 Pro,
   one of the commonest widths there is -- sits at 24.4rem, and it was landing
   in here and getting six unlabelled icons. A strip that scrolls sideways with
   readable labels beats one that fits and cannot be read. */
@media (max-width: 21rem) {
  .am-navitem:not([aria-selected="true"]) .am-navitem-label,
  .am-navitem:not([aria-selected="true"]) .am-navitem-meta {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
  }
}


/* --- No-JS ---------------------------------------------------------------
   Without script nothing is hidden: every section is on the page in order,
   which is exactly the screen this replaced. It is worse to navigate and it
   still saves. The rail is dropped rather than left as a row of buttons that
   do nothing. */

.am-editor:not(.is-enhanced) .am-editor-rail {
  display: none;
}

.am-editor:not(.is-enhanced) .am-editor-body {
  grid-template-columns: minmax(0, 1fr);
}

.am-editor:not(.is-enhanced) .am-savebar-status {
  display: none;
}


/* --- The publish confirmation --------------------------------------------
   Private -> public, and nothing else on this screen, opens a dialog. See the
   markup in americon-project-details.php for why that is the only one.

   A <dialog>, so the backdrop, the focus trap, Esc-to-close and the aria-modal
   semantics are the browser's and not a reimplementation of them -- the same
   choice the shortcut overlay in style.css makes. Colours are the theme's
   danger tokens rather than hex: the contrast checker measures tokens, and a
   hand-written red here is a red nothing tests. */

.am-confirm {
  width: min(32rem, calc(100vw - 2rem));
  padding: 0;
  border: 1px solid var(--am-border);
  border-radius: var(--am-radius-lg);
  background: var(--am-surface);
  color: var(--am-text);
  box-shadow: var(--am-shadow-lg);
}

.am-confirm::backdrop {
  background: rgb(0 0 0 / .5);
}

/* The one stripe of colour. The buttons below carry the rest of the weight;
   a fully red panel reads as an error that has already happened rather than a
   question about one that has not. */
.am-confirm--danger {
  border-top: 3px solid var(--am-danger);
}

.am-confirm-body {
  display: grid;
  gap: var(--am-gap);
  padding: var(--am-gap-lg);
  margin: 0;
}

.am-confirm-title {
  display: flex;
  align-items: center;
  gap: .5rem;
  margin: 0;
  font-size: var(--am-text-lg);
  color: var(--am-danger-ink);
}

.am-confirm-title svg {
  flex: none;
  width: 1.25rem;
  height: 1.25rem;
}

.am-confirm-lede,
.am-confirm-note {
  margin: 0;
  font-size: var(--am-text-sm);
  line-height: 1.55;
}

.am-confirm-note {
  color: var(--am-text-muted);
}

/* The consequences, one per line and countable. This is the part somebody
   actually reads, so it is not prose. */
.am-confirm-list {
  display: grid;
  gap: .4rem;
  margin: 0;
  padding: 0 0 0 1.1rem;
  font-size: var(--am-text-sm);
  line-height: 1.5;
}

.am-confirm-list li {
  padding-left: .15rem;
}

/* The acknowledgement. Sunk, so it reads as a control and not as one more
   sentence -- it is the thing standing between here and the button. */
.am-confirm-ack {
  display: flex;
  align-items: flex-start;
  gap: .6rem;
  padding: .7rem .85rem;
  border: 1px solid var(--am-border);
  border-radius: var(--am-radius);
  background: var(--am-surface-sunk);
  font-size: var(--am-text-sm);
  line-height: 1.45;
  cursor: pointer;
}

.am-confirm-ack input {
  flex: none;
  margin-top: .15rem;
}

.am-confirm-actions {
  display: flex;
  justify-content: flex-end;
  gap: .5rem;
  flex-wrap: wrap;
}

/* Disabled until the box is ticked, and it has to look it: a button that
   ignores the click without saying why is indistinguishable from one that is
   broken. */
.am-confirm-actions .btn:disabled {
  opacity: .5;
  cursor: not-allowed;
}

@media (max-width: 26rem) {
  .am-confirm-actions {
    flex-direction: column-reverse;
  }

  .am-confirm-actions .btn {
    width: 100%;
  }
}


/* --- The draft bar -------------------------------------------------------
   Above everything, because until Publish is pressed every other statement on
   this screen about who can see the project is in the future tense.

   Accent, not warning: a draft is the normal state for a project somebody is
   still working on, and colouring it as a problem would make the state people
   are supposed to use look like one to escape. It earns its prominence from
   position and from carrying the primary button, not from being loud. */

.am-draftbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--am-gap);
  margin-bottom: var(--am-gap);
  padding: var(--am-gap);
  border: 1px solid var(--am-border);
  border-left: 3px solid var(--am-accent);
  border-radius: var(--am-radius);
  background: var(--am-surface-sunk);
}

.am-draftbar-main {
  flex: 1 1 22rem;
}

.am-draftbar-title {
  display: flex;
  align-items: center;
  gap: .5rem;
  margin: 0 0 .25rem;
  font-size: var(--am-text-sm);
  font-weight: 600;
  color: var(--am-text);
}

.am-draftbar-body {
  margin: 0;
  font-size: var(--am-text-sm);
  line-height: 1.55;
  color: var(--am-text-muted);
}

.am-draftbar-actions {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
}


/* --- "This is public" ----------------------------------------------------
   The post-hoc question, above the rail on a freshly created public project.
   See render() for why it is here and not on the create form.

   Warning tokens rather than danger: nothing has gone wrong yet, and a red
   panel over a project somebody published on purpose -- half of them -- is the
   thing that gets the next one dismissed unread. It reads as loud, once, and
   then it is answered and gone. */

.am-publiced {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--am-gap);
  margin-bottom: var(--am-gap);
  padding: var(--am-gap);
  border: 1px solid var(--am-warn-ink);
  border-left-width: 3px;
  border-radius: var(--am-radius);
  background: var(--am-surface-sunk);
}

.am-publiced-main {
  flex: 1 1 22rem;
}

.am-publiced-title {
  display: flex;
  align-items: center;
  gap: .45rem;
  margin: 0 0 .25rem;
  font-size: var(--am-text-sm);
  font-weight: 600;
  color: var(--am-warn-ink);
}

.am-publiced-title svg {
  flex: none;
  width: 1rem;
  height: 1rem;
}

.am-publiced-body {
  margin: 0;
  font-size: var(--am-text-sm);
  line-height: 1.55;
  color: var(--am-text-muted);
}

/* Both answers, side by side and the same size. Making "keep it public" a
   quieter control than "make it private" would push people toward one answer
   to a question only they can answer. */
.am-publiced-actions {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
}


/* --- Bidding closed early / open past its date ---------------------------
   Shown ONLY when the bid status and the bid date disagree -- see render().
   A project whose badge and countdown already agree gets no bar, which is
   what keeps this one worth reading on the few that do.

   Borrowed shape from the draft bar rather than a new one: same position,
   same anatomy, same job -- one sentence of state and the control that ends
   it. The default is deliberately quiet: closing a bid early is a normal
   decision somebody made on purpose, and colouring it as a fault would make
   the ordinary case look like an incident. The --warn variant is for the
   other direction, which nothing will resolve on its own. */

.am-bidbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--am-gap);
  margin-bottom: var(--am-gap);
  padding: var(--am-gap);
  border: 1px solid var(--am-border);
  border-left: 3px solid var(--am-border-strong);
  border-radius: var(--am-radius);
  background: var(--am-surface-sunk);
}

.am-bidbar--warn {
  border-color: var(--am-warn-ink);
  border-left-width: 3px;
}

.am-bidbar-main {
  flex: 1 1 22rem;
}

.am-bidbar-title {
  display: flex;
  align-items: center;
  gap: .45rem;
  margin: 0 0 .25rem;
  font-size: var(--am-text-sm);
  font-weight: 600;
  color: var(--am-text);
}

.am-bidbar--warn .am-bidbar-title {
  color: var(--am-warn-ink);
}

.am-bidbar-title svg {
  flex: none;
  width: 1rem;
  height: 1rem;
}

.am-bidbar-body {
  margin: 0;
  font-size: var(--am-text-sm);
  line-height: 1.55;
  color: var(--am-text-muted);
}

.am-bidbar-actions {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
}

/* --- "Who should hear about this?" ---------------------------------------
   The unanswered question, below the statement it belongs to rather than in a
   bar of its own -- it is the same event, and two stacked bars about one
   thing get skimmed as one.

   Full width because it holds a compose box. Separated by a rule rather than
   by a second background: it is part of this bar, not a panel inside it. */

.am-bidbar-ask {
  flex: 1 1 100%;
  padding-top: var(--am-gap);
  border-top: 1px solid var(--am-border);
}

.am-bidbar-asktitle {
  margin: 0 0 .25rem;
  font-size: var(--am-text-sm);
  font-weight: 650;
  color: var(--am-text);
}

/* The compose box is a plain reading measure. Full-bleed across a wide bar
   would give a 140-character line in a textarea, which is where an email that
   reads fine on screen turns out to be unreadable in Outlook. */
.am-bidbar-ask .am-notify-form {
  max-width: 44rem;
}

/* "They already know" is a real answer and has to be reachable, but it is not
   the one to reach for by default. A link-weight control beside a primary
   button is the honest ranking of the two. */
.am-bidbar-skip {
  margin-top: .35rem;
}

.am-bidbar-skip .btn-link {
  padding-left: 0;
  font-size: var(--am-text-sm);
  color: var(--am-text-muted);
}

/* The close/reopen control in the header, beside the badge it changes. A
   bare <form> is a block box, which would break the badge row onto its own
   line; the row is flex, so the form only has to stop being one. */
.am-bidform {
  display: inline-flex;
  margin: 0;
}


/* --- "Pick one" ----------------------------------------------------------
   The create form's visibility group ships unanswered, on purpose. This line
   says so, and the script removes it the moment either card is chosen. */

.am-choices-hint {
  margin: .6rem 0 0;
  font-size: var(--am-text-xs);
  line-height: 1.5;
  color: var(--am-text-muted);
}


/* --- The head and the bars, on a screen that does not scroll ---------------
   Same gate as the viewport cap in the theme's 4.2d, and it has to be: these
   rules take height out of the furniture on the assumption that the panel
   below is going to want it. Where the cap does not apply the page scrolls,
   the extra air is free, and none of this should fire.

   The edit screen opens with more above the rail than the create form ever
   has: eyebrow, title, location and deadline, a row of badges and buttons, and
   on a draft a bar explaining what "draft" means. Measured, that is close to a
   third of a 900px window spent before the first field -- and the panel
   underneath is the part somebody came here to use.

   Nothing is removed. The title keeps its eyebrow, the draft bar keeps both
   its sentences, and the badges stay where they are. What goes is the space
   between them, which was set for a document that scrolled. */

@media (min-width: 64rem) and (min-height: 34rem) {

  .am-editor.is-enhanced .am-editor-head {
    gap: var(--am-gap-sm) var(--am-gap);
    align-items: center;   /* the badge row rides the title block, not its top */
  }

  /* The eyebrow, the title and the sub-line are one block and should read as
     one. Their default rhythm is a heading in a document; here it is a nameplate
     on a tool. */
  .am-editor.is-enhanced .am-editor-title {
    margin-top: 0;
    line-height: 1.15;
  }

  .am-editor.is-enhanced .am-editor-sub {
    margin-top: .2rem;
  }

  /* The draft and bid-state bars carry the same padding as a panel, which is
     right when they are one item in a scrolling column and too much when they
     are a strip between the title and the work. The left edge -- the accent
     that says which bar this is -- is untouched: it is the part doing the
     work of being noticed. */
  .am-editor.is-enhanced > .am-draftbar,
  .am-editor.is-enhanced > .am-bidbar,
  .am-editor.is-enhanced > .am-publiced {
    padding: var(--am-gap-sm) var(--am-gap);
    gap: var(--am-gap-sm) var(--am-gap);

    /* Their own bottom margin is from when they sat in a document that
       scrolled. The column that holds them has a gap of its own now, and the
       two together read as a gutter somebody forgot to close. */
    margin-bottom: 0;
  }

  .am-editor.is-enhanced > .am-draftbar .am-draftbar-body,
  .am-editor.is-enhanced > .am-bidbar .am-bidbar-body {
    line-height: 1.45;
  }

  /* The rail's own footer. Its three lines of padding are a third of a nav
     item, and it sits under a list that has just spent its height. */
  .am-editor.is-enhanced .am-editor-status {
    padding: .5rem .65rem;
  }


  /* --- Overview, in one screen -------------------------------------------
     Overview is the section people open by reflex and the one that was
     always taller than the panel it lives in: eight fields, two cards, a
     link and a list of forty trades. Everything above the trades is a fixed
     number of pixels, so the panel scrolled by however much the trade list
     ran over -- and the first thing off the bottom was the invite link,
     which is the thing most visits to this screen are for.

     What follows is not a smaller font. It is one row where there were two,
     one group where there were two boxes, and one block -- the trade list --
     allowed to be whatever is left. The fields do not move and nothing is
     hidden behind a control. */

  /* Name, city and state read as one line: what this project IS.
     Two rows for three short fields spent a label, a box and a gap on the
     shape of the grid rather than on anything in it. The state track is
     fixed because a <select> is sized by its longest option -- "WI —
     Wisconsin" -- and not by its share of a row; the other two divide what
     is left, the name taking the larger part. */
  .am-editor.is-enhanced .am-formgrid--identity {
    grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr) 10.5rem;
  }

  /* The name gives up its full-width span here -- it is the first of three
     cells now, not a row of its own. Below this gate it keeps it.

     By its own class and not by `> .am-formgrid-full`: Scope of work is in
     this grid too and is full-width for a reason no window size changes. A
     rule that took the span off "whatever spans the row" would have put a
     2,000-character textarea in a third of one. */
  .am-editor.is-enhanced .am-formgrid--identity > .am-field--name {
    grid-column: auto;
  }

  /* The panel's own rhythm. A section head that carries a bottom margin AND
     sits in a gapped column puts two gutters between the hint and the first
     label; the gap is the one that belongs to the column, so it is the one
     that stays. */
  .am-editor.is-enhanced .am-editor-panel > .am-panel-head {
    margin-bottom: 0;
  }

  /* Flex, not the panel's default grid, and only here.

     A grid row is sized by its content and there is no way to say "this one
     takes the remainder" without naming every row above it -- which goes
     stale the first time a field is added. In a column of flex items the
     rule is on the item that stretches, and the ones above it are furniture
     by default. :not([hidden]) so this never outranks the attribute that
     closes a section. */
  .am-editor.is-enhanced .am-editor-panel[data-am-panel="overview"]:not([hidden]) {
    display: flex;
    flex-direction: column;
    gap: var(--am-gap-sm);
  }

  .am-editor.is-enhanced .am-editor-panel[data-am-panel="overview"] > * {
    flex: none;
  }

  .am-editor.is-enhanced .am-choice {
    padding: .6rem .8rem;
  }

  /* The trade list takes what is left.

     It is the only block on this panel whose content has no natural end --
     forty trades against eight fields that are eight fields on every project
     -- so it is the one that should absorb a short window rather than push
     the rest off the bottom. The floor is three rows and the filter above
     them: below that the list is not a list, and the panel is allowed to
     scroll again instead. */
  .am-editor.is-enhanced .am-tradefield {
    flex: 1 1 auto;
    min-height: 9rem;
    display: flex;
    flex-direction: column;
  }

  .am-editor.is-enhanced .am-tradefield > legend,
  .am-editor.is-enhanced .am-tradefield .am-tradebox-head,
  .am-editor.is-enhanced .am-tradefield .am-tradebox-empty {
    flex: none;
  }

  .am-editor.is-enhanced .am-tradefield > .am-tradebox {
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    flex-direction: column;
  }

  /* The picker takes its own scroll back.

     The theme lifts its 14rem cap in this mode (style.css, 4.2d) because a
     list that scrolls inside a panel that also scrolls is two scrollbars a
     few pixels apart, and no way to tell by looking which one the wheel
     drives. That argument ends when the panel stops scrolling: this is the
     only scroll on the screen now, and it belongs to the one thing here that
     is genuinely longer than a screen. */
  .am-editor.is-enhanced .am-tradefield .am-trade-picker {
    flex: 1 1 auto;
    min-height: 0;
    max-height: none;
    overflow-y: auto;
    overscroll-behavior: contain;
    scrollbar-width: thin;
  }
}
