/* Per-child Apps workspace.
 *
 * The behavior remains in app.js and js/apps.js. This sheet only composes the
 * two scopes the parent needs to distinguish: standing child-wide rules and
 * device delivery and device-settings routes. It also bounds long loaded lists
 * without removing a single row or control from the DOM. */

#appsMount,
#appsMount > .apps-scope-card,
.apps-context-content,
.apps-scope-copy,
.apps-delivery-pane,
#appsCard,
#invList,
.invDecisionGroup,
.invMoreRows,
.invBacklogRows { min-width: 0; }

/* One context card, two responsibilities. The divider does more useful work
   than two unrelated full-width cards and remains legible with one device. */
#appsMount > .apps-scope-card {
  display: block;
  margin: 0;
  padding: 0;
  overflow: hidden;
}
.apps-context-content {
  display: grid;
  grid-template-columns: minmax(0, .9fr) minmax(0, 1.1fr);
  gap: 0;
}
.apps-context-summary { display: none; }
.apps-scope-copy,
.apps-delivery-pane { padding: 18px 20px; }
.apps-delivery-pane { border-left: 1px solid var(--line); }
.apps-phone-copy { display: none; }
.apps-scope-head,
.apps-delivery-head {
  align-items: flex-start;
  flex-wrap: wrap;
  margin-bottom: 8px;
}
.apps-scope-head > .sect,
.apps-delivery-head > .sect { min-width: 180px; }
.apps-scope-copy > .help,
.apps-delivery-details > .apps-delivery-help,
.apps-delivery-pane > .muted { margin: 0 0 14px; line-height: 1.5; }

/* Classification belongs to Processes. This is a route with an explanation,
   not an extra policy toggle and not a state-coloured status card. */
.apps-process-route {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: 16px;
  padding: 12px;
  border: 1px solid var(--line);
  border-radius: 13px;
  background: color-mix(in srgb, var(--dusk2) 78%, var(--dusk));
}
.apps-process-copy { flex: 1 1 240px; min-width: 0; }
.apps-process-copy > b { display: block; color: var(--cloud); font-size: 13px; }
.apps-process-copy > .asub {
  display: block;
  margin-top: 3px;
  color: var(--haze);
  font-size: 12px;
  font-weight: 500;
  line-height: 1.45;
}
/* This follows the generic `.asub` display rule so the short phone sentence
   does not also appear beside the full desktop explanation. */
.apps-process-copy > .apps-phone-copy { display: none; }
.apps-process-route > .ghost { flex: none; min-height: 40px; }

/* The delivery summary chip sits at the end of the head row, immediately
   before Check again — owner brief 2026-09-20: "Delivery to devices ·
   🟠 0 of 3 confirmed · Check again". It replaced a neutral `.badge` stating
   only the device count; the rule that pushed that badge here is kept, now
   pointed at the chip. `.badge`'s own rule is gone because nothing in this
   head is a `.badge` any more. */
.apps-delivery-head > .apps-delivery-confirmed { margin-left: auto; }
.apps-delivery-head > .apps-refresh {
  flex: none;
  min-height: 36px;
  padding: 7px 10px;
  font-size: 11.5px;
}
.apps-delivery-details { min-width: 0; }
.apps-delivery-summary { display: none; }
.apps-device-list { display: grid; gap: 8px; }
.apps-device-list .appsdelrow {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto auto;
  grid-template-areas: "avatar name state action";
  align-items: center;
  gap: 10px;
  margin: 0;
}
.apps-device-list .appsdelrow > .avatar { grid-area: avatar; }
.apps-device-list .appsdelrow > .an { grid-area: name; }
.apps-device-list .appsdelrow > .pill { grid-area: state; justify-self: end; }
.apps-device-list .appsdelrow > .apps-device-action {
  grid-area: action;
  justify-self: end;
  min-height: 38px;
  padding: 7px 10px;
  font-size: 11.5px;
}

.apps-device-more,
.invMoreGroup { min-width: 0; }
.apps-device-more > summary,
.invMoreGroup > summary,
details.invGroup > summary {
  cursor: pointer;
  list-style: none;
  color: var(--cloud);
  font-size: 12.5px;
  font-weight: 750;
  line-height: 1.3;
}
.apps-device-more > summary::-webkit-details-marker,
.invMoreGroup > summary::-webkit-details-marker,
details.invGroup > summary::-webkit-details-marker { display: none; }
.apps-device-more > summary::before,
.invMoreGroup > summary::before,
details.invGroup > summary::before { content: "▸ "; color: var(--attention-text); }
.apps-device-more[open] > summary::before,
.invMoreGroup[open] > summary::before,
details.invGroup[open] > summary::before { content: "▾ "; }
.apps-device-more > summary { padding: 9px 2px 5px; }
.apps-device-more[open] > .appsdelrow { margin-top: 8px; }

/* The list card has one outer frame. Search, filters, and decision groups are
   regions inside it rather than another run of cards-within-cards. */
#appsCard > .sect { margin-bottom: 10px; }
#appsCard > .screen-help { margin: 0 0 14px; }
#appsCard > .rowline {
  display: grid;
  grid-template-columns: minmax(220px, 1fr) minmax(150px, 210px);
  gap: 10px;
  margin: 0 0 10px;
}
#appsCard > .rowline > .inp { width: 100%; min-width: 0; }
#appsCard > #invFilters {
  margin: 0 0 14px;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--line);
}
#invList { display: grid; gap: 12px; }
#invList > .muted:only-child {
  margin: 0;
  padding: 20px;
  border: 1px dashed var(--line);
  border-radius: 14px;
  background: color-mix(in srgb, var(--dusk2) 58%, transparent);
  text-align: center;
}

.invDecisionGroup,
details.invGroup {
  margin: 0;
  padding: 14px;
  border: 1px solid var(--line);
  border-radius: 15px;
  background: color-mix(in srgb, var(--dusk2) 62%, var(--dusk));
}
.invDecisionGroup.invNewGroup { border-left: 4px solid var(--sky); }
.invDecisionGroup.invAllowedGroup { border-left: 4px solid var(--mint); }
.invDecisionGroup.is-empty { padding-block: 12px; }
.invGroupTitleRow {
  display: flex;
  align-items: center;
  gap: 9px;
  margin-bottom: 8px;
}
.invGroupTitleRow > .invGroupHead {
  flex: 1;
  min-width: 0;
  margin: 0;
  font-size: 14px;
}
.invGroupTitleRow > .badge { flex: none; }
.invDecisionGroup > .help,
.invDecisionGroup > .fineprint,
details.invGroup > .help { margin: 0 0 12px; max-width: 78ch; }
.invDecisionGroup > .muted { margin: 4px 0 0; }
.invDecisionGroup > .arow,
.invMoreRows > .arow,
.invBacklogRows > .arow { margin: 0; }

/* On wide screens every row retains its exact platform-specific effect line.
   The group disclosure is the phone replacement for those repeated lines. */
.invMobileEffect { display: none; }

/* Rows beyond first paint remain a single disclosure away, but opening it
   does not create a multi-thousand-pixel page. The region is keyboard
   focusable in app.js and has an explicit accessible label. */
.invMoreGroup { margin-top: 10px; }
.invMoreGroup > summary {
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: 11px;
  background: var(--dusk);
}
.invMoreRows,
.invBacklogRows {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 8px;
  max-height: 440px;
  margin-top: 10px;
  padding: 2px 5px 2px 2px;
  overflow-y: auto;
  overscroll-behavior-block: contain;
  scrollbar-gutter: stable;
  border-radius: 11px;
}
.invMoreRows:focus-visible,
.invBacklogRows:focus-visible {
  outline: 2px solid var(--glow);
  outline-offset: 3px;
}
details.invGroup > summary { padding: 2px 0 6px; }
details.invGroup[open] > summary { margin-bottom: 4px; }

/* Two app columns are useful only when each row still has room for its name,
   time, switch and New-row actions. Below this width the single column scans
   faster and does not squeeze controls. */
@media (min-width: 1200px) {
  .invDecisionGroup {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 8px 10px;
  }
  .invDecisionGroup > .invGroupTitleRow,
  .invDecisionGroup > .help,
  .invDecisionGroup > .fineprint,
  .invDecisionGroup > .muted,
  .invDecisionGroup > .invMoreGroup { grid-column: 1 / -1; }
  .invMoreRows,
  .invBacklogRows { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 899px) {
  .apps-context-content { grid-template-columns: minmax(0, 1fr); }
  .apps-delivery-pane {
    border-top: 1px solid var(--line);
    border-left: 0;
  }
}

@media (max-width: 560px) {
  /* The child shell already names the child and the selected Apps tab. Fold
     those repeated labels into one identity row, while retaining All tablets
     as a real 44px back control in that same row. */
  #inv:not(.hide) { position: relative; }
  #inv > #fc-head-apps {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    align-items: center;
    min-height: 56px;
    padding: 9px 62px 9px 12px;
  }
  #fc-head-apps > .child-headtop { display: contents; }
  #fc-head-apps .ov-eyebrow,
  #fc-head-apps .ov-sub,
  #fc-head-apps .child-headtop > .pill { display: none; }
  #fc-head-apps .ov-greet {
    margin: 0;
    font-size: 20px;
    line-height: 1.1;
  }
  #inv > .toprow {
    position: absolute;
    z-index: 2;
    top: 6px;
    right: 10px;
    width: 44px;
    height: 44px;
    margin: 0;
  }
  #inv > .toprow > .who { display: none; }
  #invBackBtn {
    width: 44px;
    min-width: 44px;
    min-height: 44px;
    padding: 0;
    font-size: 0;
    line-height: 0;
  }
  #invBackBtn::before {
    content: "←";
    font-size: 19px;
    line-height: 1;
  }

  /* The app list is the phone task. Scope and delivery remain truthful in a
     compact summary, with every explanation and route one tap underneath. */
  #appsMount > .apps-context-details { display: block; }
  #appsMount > .apps-context-details:not([open]) > .apps-context-content { display: none; }
  .apps-context-summary {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas:
      "title arrow"
      "states states";
    align-items: center;
    gap: 7px 10px;
    min-height: 60px;
    padding: 10px 12px;
    cursor: pointer;
    list-style: none;
  }
  .apps-context-summary::-webkit-details-marker { display: none; }
  .apps-context-summary::after {
    content: "▸";
    grid-area: arrow;
    color: var(--attention-text);
    font-weight: 800;
  }
  .apps-context-details[open] > .apps-context-summary {
    border-bottom: 1px solid var(--line);
  }
  .apps-context-details[open] > .apps-context-summary::after { content: "▾"; }
  .apps-context-title {
    grid-area: title;
    min-width: 0;
    color: var(--cloud);
    font-size: 13px;
    font-weight: 800;
  }
  .apps-context-states {
    grid-area: states;
    display: flex;
    flex-wrap: wrap;
    gap: 5px;
    min-width: 0;
  }

  .apps-scope-copy,
  .apps-delivery-pane { padding: 13px 14px; }
  .apps-wide-copy,
  .apps-process-copy > .apps-wide-copy { display: none; }
  .apps-phone-copy,
  .apps-process-copy > .apps-phone-copy { display: block; }
  .apps-scope-head { margin-bottom: 5px; }
  .apps-scope-head > .sect { min-width: 0; }
  .apps-scope-copy > .help { margin-bottom: 9px; line-height: 1.4; }
  .apps-process-route {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
    gap: 9px;
    margin-top: 10px;
    padding: 10px;
  }
  /* `.apps-process-copy` has a horizontal flex basis on desktop. In this
     compact phone grid it must size from its content instead. */
  .apps-process-copy { flex: none; }
  .apps-process-copy > .asub { line-height: 1.35; }
  .apps-process-route > .ghost { width: auto; min-height: 44px; padding-inline: 10px; }
  .apps-delivery-head {
    flex-wrap: nowrap;
    align-items: center;
    gap: 10px;
    margin-bottom: 8px;
  }
  .apps-delivery-head > .sect { min-width: 0; flex: 1 1 auto; }
  /* ONE SUMMARY PER WIDTH, NEVER TWO. Below 560px `.apps-delivery-summary`
     below is `display: flex` and carries the same state as this chip, split
     into "{n} applied · {n} pending" on the disclosure that opens the device
     list — so showing the head chip too would be the duplicate summary the
     owner brief rules out. Above 560px the reverse holds: the summary is
     `display: none` (see the base rule) and this chip is the only statement,
     which is why the hide is scoped to this breakpoint and not written into
     the base rule.

     CHECKED BY HAND, not just by eye (the ed3eaf68 shape): the only JS that
     writes text into `.apps-delivery-confirmed` is deliveryPane()'s own
     ctx.elem() call, which rebuilds the node on every paint. No
     `.textContent =` / `.innerHTML =` site anywhere in public/js targets it
     or a child of it, and the state it carries is still on screen at this
     width through `.apps-delivery-summary`. Verified at 375px with a real
     three-device household: "0 applied · 3 pending" visible. */
  .apps-delivery-head > .apps-delivery-confirmed { display: none; }
  .apps-delivery-head > .apps-refresh {
    flex: none;
    width: auto;
    min-height: 44px;
    margin-left: auto;
    padding-inline: 10px;
  }
  .apps-delivery-summary {
    display: flex;
    align-items: center;
    gap: 7px;
    min-height: 46px;
    padding: 8px 10px;
    border: 1px solid var(--line);
    border-radius: 12px;
    background: var(--dusk2);
    cursor: pointer;
    list-style: none;
  }
  .apps-delivery-summary::-webkit-details-marker { display: none; }
  .apps-delivery-summary::after {
    content: "▸";
    margin-left: auto;
    color: var(--attention-text);
    font-weight: 800;
  }
  .apps-delivery-details[open] > .apps-delivery-summary::after { content: "▾"; }
  .apps-delivery-summary > .pill { white-space: nowrap; }
  .apps-delivery-separator { color: var(--haze); }
  .apps-delivery-details[open] > .apps-delivery-summary { margin-bottom: 10px; }
  .apps-delivery-details > .apps-delivery-help { margin-bottom: 10px; }
  .apps-device-list .appsdelrow {
    grid-template-columns: auto minmax(0, 1fr) auto;
    grid-template-areas:
      "avatar name state"
      ". action action";
    align-items: start;
  }
  .apps-device-list .appsdelrow > .apps-device-action {
    width: 100%;
    min-height: 44px;
  }
  /* Put reference help beside the title and search beside sort. This turns
     the first SE viewport into an app workspace instead of an intro page. */
  #appsCard {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    column-gap: 8px;
  }
  #appsCard > .sect {
    grid-column: 1;
    grid-row: 1;
    align-self: center;
    margin: 0 0 10px;
  }
  #appsCard > .screen-help {
    grid-column: 2;
    grid-row: 1;
    align-self: start;
    margin: 0 0 10px;
  }
  #appsCard > .screen-help > summary {
    display: flex;
    align-items: center;
    min-height: 44px;
    padding: 8px 10px;
    white-space: normal;
  }
  /* Long translated help labels must not consume the Apps title track. Keep
     the closed disclosure as a familiar 44px info control; its full localized
     text remains the accessible name and returns visibly when opened. */
  #appsCard > .screen-help:not([open]) {
    width: 44px;
    height: 44px;
  }
  #appsCard > .screen-help:not([open]) > summary {
    justify-content: center;
    width: 44px;
    height: 44px;
    padding: 0;
    overflow: hidden;
    color: transparent;
    font-size: 0;
  }
  #appsCard > .screen-help:not([open]) > summary::before {
    content: "ⓘ";
    color: var(--attention-text);
    font-size: 19px;
    line-height: 1;
  }
  #appsCard > .screen-help[open] {
    grid-column: 1 / -1;
    grid-row: 2;
  }
  #appsCard > :not(.sect):not(.screen-help) { grid-column: 1 / -1; }
  #appsCard > .rowline {
    grid-template-columns: minmax(0, 1fr) 126px;
    gap: 8px;
  }
  .invDecisionGroup,
  details.invGroup { padding: 12px; }
  .invMobileEffect {
    display: block;
    margin: 8px 0 10px;
    border-top: 1px solid var(--line);
    border-bottom: 1px solid var(--line);
  }
  .invMobileEffect > summary {
    min-height: 44px;
    padding: 11px 2px;
    color: var(--cloud);
    cursor: pointer;
    font-size: 12px;
    font-weight: 750;
    list-style: none;
  }
  .invMobileEffect > summary::-webkit-details-marker { display: none; }
  .invMobileEffect > summary::before { content: "▸ "; color: var(--attention-text); }
  .invMobileEffect[open] > summary::before { content: "▾ "; }
  .invMobileEffect > .fineprint { margin: 0 0 10px 16px; }

  /* App rows become a stable name/switch header with usage beneath it. The
     long platform effect is still available once per group above, so it no
     longer makes every app card repeat the same paragraph. */
  #invList .arow {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 46px;
    grid-template-areas:
      "name switch"
      "time switch";
    align-items: start;
    gap: 5px 10px;
    padding: 10px 11px;
  }
  #invList .arow > .an { grid-area: name; }
  #invList .arow > .atime {
    grid-area: time;
    min-width: 0;
    max-width: none;
    text-align: left;
    font-size: 11.5px;
  }
  #invList .arow > .sw { grid-area: switch; justify-self: end; }
  #invList .arow .an > .asub.inv-description {
    display: block;
    margin-top: 3px;
    line-height: 1.4;
  }
  #invList .arow .an > .asub.inv-description::before { content: none; }
  #invList .arow .an > .asub.inv-block-effect { display: none; }
  #invList .arow.new > .invRowActions {
    grid-area: actions;
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    grid-template-areas:
      "allow hide"
      "limit limit";
    gap: 7px;
    width: 100%;
    margin-top: 4px;
  }
  #invList .arow.new {
    grid-template-areas:
      "name switch"
      "time switch"
      "actions actions";
  }
  .invRowActions > .invActionAllow { grid-area: allow; }
  .invRowActions > .invActionHide { grid-area: hide; }
  .invRowActions > .invActionLimit { grid-area: limit; }
  .invRowActions > .ghost { width: 100%; min-width: 0; min-height: 44px; }
  .invMoreRows,
  .invBacklogRows { max-height: 390px; }
}

@media (max-width: 340px) {
  #appsCard > .rowline { grid-template-columns: minmax(0, 1fr); }
}

/* The light theme relies on visible panel boundaries rather than shadow alone.
   Text continues to use the already-audited cloud/haze palette. */
:root[data-theme="light"] .apps-process-route,
:root[data-theme="light"] .invDecisionGroup,
:root[data-theme="light"] details.invGroup {
  background: #F5F8FB;
  border-color: #AEBECE;
}
:root[data-theme="light"] .apps-delivery-pane { border-color: #AEBECE; }
:root[data-theme="light"] .invMoreGroup > summary { background: #E8EFF6; }
:root[data-theme="light"] .apps-device-more > summary,
:root[data-theme="light"] .invMoreGroup > summary,
:root[data-theme="light"] details.invGroup > summary { color: #263F59; }

/* ==========================================================================
   ADD AN APP — ONE FULL-WIDTH UTILITY PANEL (owner brief, 2026-09-21)

   WHAT WAS WRONG: a half-width card in track one beside an empty track two
   (fixed where it belongs, in app.css's per-child grid-trap block, beside
   #appsCard's own span), holding two stacked full-width buttons that gave a
   supporting utility more weight than the list it supports.

   WHAT IT IS NOW: the words on the left, the two actions grouped on the right,
   the identifier note beneath — one panel on the same edges as the list above
   it. The card keeps plain `.card`, so its radius, border, background and
   padding are the page's own; nothing here repaints it.

   NO NEW COLOUR, NO NEW TOKEN, NO NEW BUTTON STYLE. Allow keeps the `.primary`
   class (its role, hover and disabled state) and is PAINTED with the design
   system's own primary-CTA token pair, `--primary-cta-gradient` /
   `--primary-cta-text` — exactly what the Devices screen's primary CTA
   (#addAnotherDeviceLink) already wears. Not `.primary`'s own literal
   gradient, and that choice is MEASURED, not taste:
     - `.primary` paints `linear-gradient(135deg, var(--glow), #8FE7FF)` with
       white glyphs in light theme. Sampled off the rendered button, white on
       that ground is 1.67:1 at worst and 2.59:1 median under the label — and
       compacting the button (below) stretches the label further into the
       pale end than the old full-width slab did.
     - The token pair is the AUDITED one: light theme darkens its endpoint to
       #207CB7 so white clears 4.54:1 "across the full gradient" (app.css,
       the light :root block), which is OWNER DECISION 2026-09-20's rule for
       glyphs. In dark theme the pair is byte-identical to `.primary`
       (glow -> #8FE7FF, ink text), so dark renders exactly as before.
   The global `.primary` is deliberately NOT changed here: 26 buttons wear it,
   which is a separate, reviewed change, not a side effect of one panel.
   What the brief took away is the OVERSIZING, and the values below that take
   it away are `.fc-actions > .primary`'s own, verbatim: the precedent for a
   primary that sits in a row of peers instead of submitting a form. Block is
   `.ghost.danger` (set in the markup), the cautionary treatment #pauseAllBtn
   and the Devices bulk action already use, light-theme #B23127 included.

   CSS-THAT-IS-BEHAVIOUR AUDIT (commit ed3eaf68's lesson), done first: nothing
   here sets display/visibility/opacity on anything JS writes into. The panel's
   one feedback path — addAppFromPicker() -> invSay() — writes #invMsg, which
   is a direct child of #inv ABOVE the list, not inside this card; no script
   writes into any #invAdd* element. The only `display` set below is `flex` on
   the two new wrappers, which carry no text of their own.
   ========================================================================== */

#invAddCard .invadd-body {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 14px 24px;
}
/* THE WORDS CLAIM A READABLE MEASURE FIRST, and the action group drops beneath
   them, intact, when the row cannot hold both. A fixed two-column row cannot
   do that. MEASURED on the shipped copy: French's two labels need about 450px
   against English's 280px, which at 1024px would have squeezed the
   explanation into a ~200px column. */
#invAddCard .invadd-copy { flex: 1 1 22rem; min-width: 0; }
/* #appsCard's own title-to-content spacing (apps.css, `#appsCard > .sect`), so
   the two cards on this screen read as one family. The help line's bottom
   margin comes off because the row gap owns that space now. */
#invAddCard .invadd-copy > .sect { margin-bottom: 10px; }
#invAddCard .invadd-copy > .help { margin-bottom: 0; }

#invAddCard .invadd-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  flex: 0 1 auto;
  min-width: 0;
}
/* ONE SHAPE FOR BOTH, so they match in height, radius, type and alignment.
   `.primary` is `width: 100%` and `margin-top: 12px` by default (it is the
   page's form-submit shape); both claims come off here, inside this group
   only. The transparent border gives `.primary` the same 1px box edge
   `.ghost` already has, so the two cannot differ by a border's height. */
#invAddCard .invadd-actions > button {
  width: auto;
  margin-top: 0;
  min-height: 44px;
  padding: 12px 16px;
  font-size: 14px;
}
/* #addAnotherDeviceLink's paint, verbatim, minus its font-weight: 750 — the
   two buttons here share one weight, because matching typography is the
   brief's own requirement for this pair. The id in this selector outranks
   `:root[data-theme="light"] .primary`'s white, so no theme override is
   needed: --primary-cta-text already IS white in light and ink in dark. */
#invAddCard .invadd-actions > .primary {
  border: 1px solid transparent;
  background: var(--primary-cta-gradient);
  color: var(--primary-cta-text);
  box-shadow: 0 8px 20px color-mix(in srgb, var(--glow) 18%, transparent);
}
#invAddCard > .fineprint { margin-top: 14px; }

/* TABLET: the words take the whole row and the action group sits under them,
   buttons still at their own width. Keyed on the same 899.98px edge where
   #inv itself stops being a grid (app.css), so the panel changes shape at the
   moment the page does rather than at a second, unrelated width. */
@media (max-width: 899.98px) {
  #invAddCard .invadd-copy { flex-basis: 100%; }
}

/* PHONE: one column, and each button the full width of the panel — a tap
   target the width of a thumb's reach, same breakpoint as this file's own
   phone block above. */
@media (max-width: 560px) {
  #invAddCard .invadd-actions { flex: 1 1 100%; flex-direction: column; }
  #invAddCard .invadd-actions > button { width: 100%; }
}
