/* ============================================================================
   screens/settings.css - organisation, users, roles and app preferences
   ----------------------------------------------------------------------------
   One stacked stage on both viewports, switched by the tab strip. There is no
   two pane workbench here on purpose: a settings form is read top to bottom and
   a second column would only halve the width every label has to fit into.

   Everything shared with other screens comes from elsewhere and is not
   redeclared here:
     components.css  .panel, .card, .res, .r-*, .av, .tag, .pill, .bdg, .note,
                     .mini-btn, .btn, .icon-btn, .empty, .ui-*  (form, table,
                     tabs, filter bar, pager, dialog)
     layout.css      .topbar, .tb-*, .content, .view-desktop, .view-mobile
     mobile.css      .phead, .pbody, .prow, .p-m, .p-tail, .banner
     tokens.css      every colour, radius, shadow, space and duration below

   What this file adds is only what exists nowhere else: the stage rhythm, the
   working day grid, the account row furniture, the permission matrix, the
   permission picker, and the Database tab (section 12, prefix .set-db-).

   Motion. settings.js rebuilds the stage on every render, so anything that
   should move on arrival is an animation that plays when its node is created;
   a transition would have nothing to transition from. Each panel, role row and
   account row carries `--i` (its index, capped at 12) and inherits the shared
   rise-in keyframes from base.css. Every duration is a --t-* token, so the
   reduced-motion rule in base.css neutralises all of it by overriding the
   tokens rather than by fighting specificity here.

   Colour rule, without exception: every value below is var(--...) from
   tokens.css. No hex, no rgba, no forced override, and no inline style: the one
   dynamic value this screen has is `--i`, written by el.style.setProperty().
   ============================================================================ */


/* ---------------------------------------------------------------------------
   1. The stage

   .content is already the desktop scroller; making it a flex column is what
   keeps the tab strip at the top of it and lets the stage grow underneath
   without either one inventing a height of its own.
   --------------------------------------------------------------------------- */
.set{
  display: flex;
  flex-direction: column;
  gap: var(--s-4);
}

.set-stage{
  display: flex;
  flex-direction: column;
  gap: var(--s-4);
  min-width: 0;
}

/* The desktop topbar cluster: the New user button next to the reload control. */
.set-tb-actions{
  display: flex;
  align-items: center;
  gap: var(--s-2);
}

/* The same two controls on the phone, pushed to the end of the title row so the
   heading and its count pill keep the left. */
.set-m-actions{
  display: flex;
  align-items: center;
  gap: var(--s-1);
  margin-inline-start: auto;
}

/* The mobile column. .pbody already supplies the flex column, the gutter and,
   through .main in layout.css, the tab bar clearance; the only change a stack
   of panels needs is a slightly wider gap between them. */
.set-mbody{
  gap: var(--s-4);
}

/* A panel arriving with the section it belongs to. `backwards` holds the start
   state through the delay, as components.css explains. */
.set-group,
.set-panel{
  animation: rise-in var(--t-base) var(--ease-out) backwards;
  animation-delay: calc(var(--stagger) * var(--i, 0));
}

/* A panel whose next answer is still in flight keeps its rows up, dimmed. It
   never collapses: a list that disappears between two pages of the same query
   is harder to follow than one that waits. */
.set-panel.is-busy{
  opacity: .6;
  transition: opacity var(--t-fast);
}

/* The read only notice above a section somebody may look at but not change. */
.set-note{
  margin: 0;
}

.set-note b{
  font-weight: 700;
}


/* ---------------------------------------------------------------------------
   2. Settings groups

   The panel heading carries the group's own icon, so the eye can find Working
   hours without reading four headings first.
   --------------------------------------------------------------------------- */
.set-group .panel-h-top > h2{
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
}

.set-group .panel-h-top > h2 .ic{
  width: 17px;
  height: 17px;
  color: var(--gold-600);
}

.set-group .panel-h .note{
  margin: 0;
}

.set-group-b{
  padding-top: var(--s-5);
}


/* ---------------------------------------------------------------------------
   3. The working week

   work_days is the one setting whose editor is not a single control. The block
   wears .ui-field so the two column form grid spans it exactly like a real
   field, and the fieldset's own chrome is cleared: the legend is the label and
   the border would draw a box nothing else in the form has.
   --------------------------------------------------------------------------- */
/* display:block, not the .ui-field flex column it borrows the grid span from: a
   <legend> inside a flex fieldset is laid out inconsistently between engines,
   and the three children here only need to stack. */
.set-days{
  display: block;
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
}

.set-days > legend{
  margin-bottom: var(--s-2);
  padding: 0;
}

.set-days > .ui-help,
.set-days > .ui-err{
  margin-top: var(--s-2);
}

/* Seven boxes that fit four to a row on a workbench and two on a phone, without
   a media query: the track decides for itself how many fit. */
.set-days-grid{
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
  gap: var(--s-1) var(--s-4);
  padding: var(--s-2) var(--s-3);
  border: 1px solid var(--gray-200);
  border-radius: var(--r-sm);
  background: var(--gray-50);
}

.set-days.is-invalid > legend{
  color: var(--red-700);
}

.set-days.is-invalid .set-days-grid{
  border-color: var(--red);
}


/* ---------------------------------------------------------------------------
   4. The account list
   --------------------------------------------------------------------------- */

/* "12 accounts matching these filters, 2 suspended accounts on this page". */
.set-summary{
  margin: 0;
  font-size: 12.5px;
  color: var(--muted);
}

/* The name cell: avatar, name, email under it. Shared by the desktop table and
   the mobile cards, because both are rendered from the same column. */
.set-uid{
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  min-width: 0;
}

.set-uid-b{
  display: flex;
  flex-direction: column;
  min-width: 0;
  line-height: 1.3;
}

.set-uid-b > b{
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  font-weight: 600;
  color: var(--ink);
}

.set-uid-b .note{
  margin: 0;
}

/* The "You" mark on the signed in account's own row. */
.set-you{
  background: var(--gold-100);
  color: var(--gold-700);
}

/* A timestamp cell: the age first, the exact stamp under it. */
.set-when{
  display: flex;
  flex-direction: column;
  line-height: 1.3;
}

.set-when > b{
  font-size: 13px;
  font-weight: 600;
  color: var(--ink);
}

.set-when .note{
  margin: 0;
}

/* The row actions, in the table and on the mobile card alike. */
.set-uacts{
  display: inline-flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--s-1);
}

/* The phone's list. Each account is one .prow with its actions on the line
   below it, so a 44px target never has to share a row with a chevron. */
.set-urows{
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
  margin: 0;
  padding: 0;
  list-style: none;
}

.set-urows > li{
  display: flex;
  flex-direction: column;
  gap: var(--s-1);
  animation: rise-in var(--t-base) var(--ease-out) backwards;
  animation-delay: calc(var(--stagger) * var(--i, 0));
}

.set-urow .p-tail{
  gap: var(--s-2);
}

.set-urow-act{
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--s-2);
  padding-inline-end: var(--s-1);
}

.set-urow-act:empty{
  display: none;
}


/* ---------------------------------------------------------------------------
   5. One account, in a dialog
   --------------------------------------------------------------------------- */
.set-udetail{
  display: flex;
  flex-direction: column;
  gap: var(--s-5);
}

.set-udetail-head{
  display: flex;
  align-items: center;
  gap: var(--s-4);
}

.set-udetail-n{
  margin: 0 0 var(--s-2);
  font-family: var(--f-disp);
  font-size: 17px;
  font-weight: 600;
  color: var(--ink);
}

.set-udetail-tags{
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-2);
}

/* Term and value, two columns on a workbench and stacked on a phone. */
.set-facts{
  display: grid;
  grid-template-columns: minmax(120px, 200px) minmax(0, 1fr);
  gap: var(--s-2) var(--s-4);
  margin: 0;
}

.set-facts dt{
  font-size: 12px;
  font-weight: 600;
  color: var(--muted);
}

.set-facts dd{
  margin: 0;
  font-size: 13.5px;
  color: var(--ink);
  overflow-wrap: anywhere;
}


/* ---------------------------------------------------------------------------
   6. The one time password

   Shown once, copied, then gone. The field is readonly rather than disabled so
   the value can still be selected and read by a screen reader.
   --------------------------------------------------------------------------- */
.set-pw{
  display: flex;
  flex-direction: column;
  gap: var(--s-4);
}

.set-pw-note{
  display: flex;
  align-items: flex-start;
  gap: var(--s-2);
  margin: 0;
  padding: var(--s-3) var(--s-4);
  border: 1px solid var(--gold-300);
  border-radius: var(--r-sm);
  background: var(--gold-100);
  font-size: 12.5px;
  line-height: 1.45;
  color: var(--gold-700);
}

.set-pw-note .ic{
  flex: none;
  width: 16px;
  height: 16px;
  margin-top: 1px;
}

.set-pw-row{
  display: flex;
  align-items: center;
  gap: var(--s-2);
}

.set-pw-v{
  flex: 1;
  min-width: 0;
  font-size: 16px;
  letter-spacing: .08em;
}

.set-pw .ui-help{
  margin: 0;
}


/* ---------------------------------------------------------------------------
   7. Roles
   --------------------------------------------------------------------------- */
.set-roles{
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
  padding-top: var(--s-4);
  padding-bottom: var(--s-4);
}

.set-role{
  animation: rise-in var(--t-base) var(--ease-out) backwards;
  animation-delay: calc(var(--stagger) * var(--i, 0));
}

.set-role .r-ic .ic{
  color: var(--gold-600);
}

/* The parts of the meta line under a role name. .r-val already supplies the
   mono face and the wrapping; these two only carry the break behaviour and the
   colour of the middot between them. */
.set-meta{
  min-width: 0;
}

.set-sep{
  color: var(--gray-400);
}

.set-role .r-name{
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-2);
}

.set-role .note .ic{
  width: 13px;
  height: 13px;
  margin-inline-end: var(--s-1);
  vertical-align: -2px;
  color: var(--gray-400);
}

/* The owner role: the API refuses to edit it, so the row says why rather than
   showing a button that would be rejected. */
.set-lock{
  background: var(--navy);
  color: var(--white);
}

.set-lock .ic{
  color: var(--gold);
}


/* ---------------------------------------------------------------------------
   8. The permission matrix

   The one place on this screen that may scroll sideways, and it does it inside
   its own container: the page body still never moves. min-width keeps the
   columns readable instead of crushing six roles into a phone's width.
   --------------------------------------------------------------------------- */
.set-mx-b{
  padding: var(--s-4);
}

.set-mx-scroll{
  overflow-x: auto;
  overscroll-behavior-x: contain;
  border: 1px solid var(--gray-200);
  border-radius: var(--r-sm);
}

.set-mx{
  min-width: 620px;
}

/* A row header is a label plus its key, not a column heading, so it drops the
   uppercase treatment and the nowrap .ui-table gives every th. */
.set-mx tbody th{
  padding: var(--s-2) var(--s-3);
  text-align: start;
  text-transform: none;
  letter-spacing: normal;
  white-space: normal;
  vertical-align: middle;
}

.set-mx tbody th > b{
  display: block;
  font-size: 13px;
  font-weight: 600;
  color: var(--ink);
}

.set-mx tbody th .note{
  margin: 0;
  font-size: 11px;
}

.set-mx thead th{
  vertical-align: bottom;
  white-space: nowrap;
}

/* A role is a proper noun, so it keeps its own casing rather than taking the
   uppercase .ui-table gives a column heading. */
.set-mx-role{
  display: block;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: normal;
  text-transform: none;
  color: var(--navy);
}

.set-mx thead th .note{
  margin: 0;
  font-size: 10.5px;
  text-transform: none;
  letter-spacing: normal;
}

/* The module band that groups the rows below it. Selected through tbody so it
   outweighs the row header rule above, which would otherwise take the band's
   uppercase away from it. */
.set-mx tbody .set-mx-group > th{
  padding: var(--s-2) var(--s-3);
  background: var(--gray-100);
  color: var(--navy);
  font-family: var(--f-ui);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  text-align: start;
}

.set-mx-yes{
  width: 17px;
  height: 17px;
  color: var(--green);
}

/* Absence is drawn, not left blank: an empty cell reads as a rendering fault.
   The sr-only sentence next to it carries the same fact to a screen reader. */
.set-mx-no{
  display: inline-block;
  width: 10px;
  height: 2px;
  border-radius: 1px;
  background: var(--gray-300);
  vertical-align: middle;
}


/* ---------------------------------------------------------------------------
   9. The permission picker

   Used twice: as the editor, and as the read only view for somebody without
   settings.manage_roles. One block, two states, so the two lists can never
   drift apart.
   --------------------------------------------------------------------------- */
.set-perm{
  display: flex;
  flex-direction: column;
  gap: var(--s-5);
}

.set-perm-t{
  display: flex;
  align-items: center;
  gap: var(--s-2);
  margin: 0 0 var(--s-2);
  font-family: var(--f-ui);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--muted);
}

.set-perm-t .ic{
  width: 15px;
  height: 15px;
  color: var(--gold-600);
}

.set-perm-grid{
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: var(--s-1) var(--s-4);
}

/* The row grows past 44px because it carries three lines; align the box with
   the first of them rather than with the middle of the block. */
.set-perm-row{
  align-items: flex-start;
  padding: var(--s-2) 0;
}

.set-perm-row .ui-checkbox{
  margin-top: 2px;
}

.set-perm-l{
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.set-perm-l > b{
  font-size: 13.5px;
  font-weight: 600;
  color: var(--ink);
}

.set-perm-l .note{
  margin: 0;
  font-size: 11px;
}


/* ---------------------------------------------------------------------------
   10. Mobile
   --------------------------------------------------------------------------- */
@media (max-width: 860px){

  /* The phone column is 520px at most, so the facts list stacks rather than
     squeezing a value into a third of it. */
  .set-facts{
    grid-template-columns: minmax(0, 1fr);
    gap: var(--s-1) 0;
  }

  .set-facts dd{
    margin-bottom: var(--s-2);
  }

  /* Contract section 4.5: every tappable control keeps its 44px floor. */
  .set-urow-act .mini-btn,
  .set-uacts .mini-btn,
  .set-role .r-act .mini-btn{
    min-width: 44px;
    min-height: 44px;
  }

  /* A copy button under the field rather than beside it: at 390px the two of
     them on one line leave the password four characters wide. */
  .set-pw-row{
    flex-direction: column;
    align-items: stretch;
  }

  .set-pw-row .btn{
    min-height: 44px;
  }

  .set-mx-b{
    padding: var(--s-3);
  }
}


/* ---------------------------------------------------------------------------
   11. Print

   A settings page is printed to be signed off or filed. The controls are
   chrome; the values, the roles and the matrix are the content.
   --------------------------------------------------------------------------- */
@media print{
  .set-tb-actions,
  .set-m-actions,
  .set-uacts,
  .set-urow-act,
  .set-role .r-act,
  .set-tabs,
  .ui-form-foot{
    display: none;
  }

  /* Nothing may be cut off at the page edge, so the matrix stops scrolling and
     prints at whatever width it needs. */
  .set-mx-scroll{
    overflow: visible;
    border: 0;
  }

  .set-group,
  .set-panel,
  .set-role,
  .set-urows > li{
    animation: none;
  }
}


/* ---------------------------------------------------------------------------
   Access, one person at a time

   The dialog behind the shield button on a user row. It is deliberately built
   from three state buttons per permission rather than a checkbox, because a
   checkbox has two states and this has three, and the third one, "whatever the
   role says", is the one that is true for almost every row. A checkbox would
   have to encode it as a shade of grey, and a shade of grey is not a thing
   anybody can press with confidence.
   --------------------------------------------------------------------------- */
.set-acc{
  display: flex;
  flex-direction: column;
  gap: var(--s-5);
}

.set-acc-roles{
  padding-block: var(--s-3);
  border-bottom: 1px solid var(--gray-200);
}

.set-acc-role-grid{
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: var(--s-1) var(--s-4);
  margin-top: var(--s-2);
}

.set-acc-role{
  align-items: flex-start;
  padding: var(--s-2) 0;
}

/* The running total sits between the roles and the switches, where a change to
   either one is visible without scrolling back. */
.set-acc-sum{
  margin: 0;
  padding: var(--s-2) var(--s-3);
  border-radius: var(--r-sm);
  background: var(--gray-50);
  font-variant-numeric: tabular-nums;
}

.set-acc-perms{
  display: flex;
  flex-direction: column;
  gap: var(--s-5);
}

.set-acc-grid{
  display: flex;
  flex-direction: column;
  gap: var(--s-1);
}

/* One permission: its name on the left, its three way switch on the right.
   Wraps to two lines on a phone, because a 44px target three times over does
   not fit beside a sentence at 320px and should not be shrunk to make it. */
.set-acc-row{
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--s-2) var(--s-4);
  padding: var(--s-3) 0;
  border-bottom: 1px solid var(--gray-100);
}

.set-acc-row:last-child{
  border-bottom: 0;
}

.set-acc-l{
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
  flex: 1 1 240px;
}

.set-acc-seg{
  display: inline-flex;
  flex: 0 0 auto;
  border: 1px solid var(--gray-200);
  border-radius: var(--r-sm);
  overflow: hidden;
  background: var(--white);
}

.set-acc-b{
  min-height: 44px;
  padding: 0 var(--s-3);
  border: 0;
  border-right: 1px solid var(--gray-200);
  background: transparent;
  color: var(--muted);
  font-family: var(--f-ui);
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
  transition: background var(--t-fast), color var(--t-fast);
}

.set-acc-b:last-child{
  border-right: 0;
}

.set-acc-b:hover:not(:disabled){
  background: var(--gray-100);
  color: var(--navy);
}

.set-acc-b:disabled{
  cursor: default;
  opacity: .6;
}

/* The three states carry the same colour language as the badges elsewhere:
   neutral for what the role decided, gold for something granted on purpose,
   red for something taken away on purpose. */
.set-acc-b.is-on{
  background: var(--navy);
  color: var(--white);
}

.set-acc-b--allow.is-on{
  background: var(--gold);
  color: var(--navy);
}

.set-acc-b--deny.is-on{
  background: var(--red);
  color: var(--white);
}

@media (max-width: 719.98px){
  .set-acc-seg{
    width: 100%;
  }

  .set-acc-b{
    flex: 1 1 0;
  }
}


/* ---------------------------------------------------------------------------
   12. Database: the runner of automatic database changes

   Drawn by settings/database.js. The tab refreshes itself every minute while
   it is on screen, so nothing here may move on a mere repaint: the arrival
   motion sits on .set-db-rise, which database.js puts on the panels only for
   the first paint after the data arrived, never on the minute refresh. When a
   refresh does change a panel, database.js keeps the node under the pointer
   where it was; the browser's own scroll anchoring is off for these blocks so
   the two never correct the same shift twice.

   Three tones, the same language as the badges elsewhere: gold for what waits
   on a person, red for what stopped or must be fixed, green for what is right.
   Every value is var(--...) from tokens.css; the only dynamic value is --i.
   --------------------------------------------------------------------------- */
.set-db-rise{
  animation: rise-in var(--t-base) var(--ease-out) backwards;
  animation-delay: calc(var(--stagger) * var(--i, 0));
}

/* A panel whose next answer is on the wire keeps its rows up, dimmed. */
.set-db-panel.is-busy{
  opacity: .6;
  transition: opacity var(--t-fast);
}

.set-db-panel,
.set-db-msg{
  overflow-anchor: none;
}

.set-db-panel .panel-h-top > h2{
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
}

.set-db-panel .panel-h-top > h2 .ic{
  width: 17px;
  height: 17px;
  color: var(--gold-600);
}

.set-db-b{
  display: flex;
  flex-direction: column;
  gap: var(--s-4);
  min-width: 0;
}

.set-db-b > p,
.set-db-card > p,
.set-db-detail > p,
.set-db-tech > p,
.set-db-cron > p,
.set-db-ctl > p{
  margin: 0;
}

/* A small heading inside a panel, the same voice as the permission picker. */
.set-db-h3{
  margin: 0;
  font-family: var(--f-ui);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--muted);
}

/* The label above a value: what it does, the database message, missing. */
.set-db-k{
  display: block;
  font-family: var(--f-ui);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--gray-600);
}

.set-db-line{
  font-size: 13.5px;
  line-height: 1.45;
  color: var(--ink);
}

/* The runner's mode and its last check, under the state badge. */
.set-db-state{
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-2) var(--s-3);
}

/* .pill is set in the mono face for counts; a mode is words. */
.set-db-pill{
  font-family: var(--f-ui);
  letter-spacing: normal;
}

/* Sentences from the server: blockers, problems, warnings. */
.set-db-list{
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.set-db-list > li{
  display: flex;
  align-items: flex-start;
  gap: var(--s-2);
  font-size: 13px;
  line-height: 1.45;
  color: var(--ink);
}

.set-db-list .ic{
  flex: none;
  width: 15px;
  height: 15px;
  margin-top: 2px;
  color: var(--gray-500);
}

.set-db-list--warn .ic{
  color: var(--gold-600);
}

.set-db-list--bad .ic{
  color: var(--red);
}

.set-db-list--info .ic{
  color: var(--green);
}

/* The files that differ from the release, while the runner waits for them. */
.set-db-files{
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-1) var(--s-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.set-db-files > li{
  padding: 2px var(--s-2);
  border-radius: var(--r-sm);
  background: var(--gray-100);
  color: var(--ink);
  overflow-wrap: anywhere;
}

/* Under Starting point: the updates applied by hand before the runner, in the
   same quiet chips as the files above. Data, never a control. */
.set-db-legacy{
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
  padding-top: var(--s-3);
  border-top: 1px solid var(--gray-200);
}

.set-db-legacy > p{
  margin: 0;
}

.set-db-legacy-list{
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-1) var(--s-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.set-db-legacy-row{
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-1) var(--s-2);
  min-width: 0;
  padding: 2px var(--s-2);
  border-radius: var(--r-sm);
  background: var(--gray-100);
}

.set-db-legacy-row > .set-db-file{
  font-size: 12px;
  font-weight: 500;
  color: var(--ink);
}

/* The switch and Pause or Resume, on one tray. */
.set-db-controls{
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--s-3) var(--s-5);
  padding: var(--s-3) var(--s-4);
  border: 1px solid var(--gray-200);
  border-radius: var(--r-sm);
  background: var(--gray-50);
}

.set-db-switch{
  flex: 1 1 280px;
  min-width: 0;
}

.set-db-ctl{
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-2) var(--s-3);
}

.set-db-paused{
  display: inline-flex;
  align-items: center;
  gap: var(--s-1);
}

.set-db-paused .ic{
  width: 13px;
  height: 13px;
}

/* A line of code with its Copy button under it. The line wraps rather than
   scrolls, so a 390px phone never scrolls sideways; copying takes the text,
   not the wrapping. */
.set-db-cron{
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
}

.set-db-copy{
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--s-2);
  min-width: 0;
}

.set-db-code{
  align-self: stretch;
  margin: 0;
  padding: var(--s-3);
  border-radius: var(--r-sm);
  background: var(--navy-900);
  color: var(--gray-50);
  line-height: 1.55;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.set-db-code--sm{
  padding: var(--s-2) var(--s-3);
  font-size: 11.5px;
}

/* The five first run steps. base.css takes every list marker away, so the
   number is drawn here as a counter in a gold disc. */
.set-db-steps{
  margin: 0;
  padding: 0;
  counter-reset: set-db-step;
}

.set-db-steps > li{
  position: relative;
  padding-inline-start: calc(24px + var(--s-3));
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--ink);
  counter-increment: set-db-step;
}

.set-db-steps > li::before{
  content: counter(set-db-step);
  position: absolute;
  inset-inline-start: 0;
  top: 0;
  display: grid;
  place-items: center;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background: var(--gold-100);
  color: var(--gold-700);
  font-size: 12px;
  font-weight: 700;
  line-height: 1;
}

.set-db-steps > li + li{
  margin-top: var(--s-5);
}

.set-db-steps > li > p{
  margin: 0;
}

.set-db-steps > li > * + *{
  margin-top: var(--s-3);
}

/* A change that waits for the owner: a gold card, one row per rule. */
.set-db-cards{
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
}

.set-db-card{
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
  min-width: 0;
  padding: var(--s-4);
  border: 1px solid var(--gold-300);
  border-radius: var(--r);
  background: var(--gold-a05);
}

/* Approved, not run yet: it waits for the runner now, not for a person, so
   it leaves the gold behind. */
.set-db-card--approved{
  border-color: var(--gray-200);
  background: var(--white);
}

.set-db-card-h{
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-2);
}

.set-db-file{
  min-width: 0;
  font-size: 13px;
  font-weight: 600;
  color: var(--navy);
  overflow-wrap: anywhere;
}

.set-db-sum > p{
  margin: var(--s-1) 0 0;
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--ink);
}

.set-db-rules{
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.set-db-rule{
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: var(--s-2) var(--s-3);
  border-left: 3px solid var(--gold);
  border-radius: var(--r-sm);
  background: var(--white);
  font-size: 13px;
  line-height: 1.45;
  color: var(--ink);
}

.set-db-rule > b{
  font-weight: 700;
  color: var(--navy);
}

.set-db-card-act{
  display: flex;
  justify-content: flex-end;
  gap: var(--s-2);
}

.set-db-card-act:empty{
  display: none;
}

.set-db-approved,
.set-db-backup,
.set-db-hint{
  display: flex;
  align-items: flex-start;
  gap: var(--s-1);
}

.set-db-approved .ic,
.set-db-backup .ic,
.set-db-hint .ic{
  flex: none;
  width: 14px;
  height: 14px;
  margin-top: 1px;
}

/* What to do next: the runner is silent, never reported, or waits for a
   deploy; a stopped change holds up every later one. */
.set-db-hint .ic{
  color: var(--gold-600);
}

.set-db-approved .ic{
  color: var(--green);
}

.set-db-backup .ic{
  color: var(--gold-600);
}

/* Show and hide a block. The open state is .is-on on the button, written by
   database.js together with aria-expanded and the block's hidden flag. */
.set-db-disc{
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
  min-width: 0;
}

.set-db-disc-t{
  display: inline-flex;
  align-items: center;
  align-self: flex-start;
  gap: var(--s-1);
  min-height: 32px;
  padding: var(--s-1) var(--s-2);
  border: 0;
  border-radius: var(--r-sm);
  background: transparent;
  color: var(--navy);
  font-family: var(--f-ui);
  font-size: 12.5px;
  font-weight: 600;
  cursor: pointer;
  transition: background var(--t-fast);
}

.set-db-disc-t:hover{
  background: var(--gray-100);
}

.set-db-disc-t .ic{
  width: 15px;
  height: 15px;
  transform: rotate(-90deg);
  transition: transform var(--t-fast);
}

.set-db-disc-t.is-on .ic{
  transform: rotate(0deg);
}

/* SQL and database messages: data, shown exactly as written. */
.set-db-sql{
  margin: 0;
  max-height: 320px;
  padding: var(--s-3);
  border: 1px solid var(--gray-200);
  border-radius: var(--r-sm);
  background: var(--gray-50);
  color: var(--ink);
  line-height: 1.5;
  white-space: pre;
  overflow: auto;
}

.set-db-sql--msg{
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

/* One change in the list: its file name, its summary and its kind. */
.set-db-ident{
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
  min-width: 0;
  line-height: 1.35;
  text-align: start;
}

.set-db-ident > b{
  font-size: 12.5px;
  font-weight: 600;
  color: var(--navy);
  overflow-wrap: anywhere;
}

.set-db-ident .note{
  font-size: 12px;
}

.set-db-notes{
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-size: 12px;
  line-height: 1.4;
  color: var(--ink);
}

/* "1.240 ms" stays on one line in the narrow Duration column. */
.set-db-num{
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

.set-db-acts{
  display: inline-flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--s-1);
}

/* The phone's change rows, drawn from the same array as the table. */
.set-db-rows{
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
  margin: 0;
  padding: 0;
  list-style: none;
}

.set-db-rows > li{
  display: flex;
  flex-direction: column;
  gap: var(--s-1);
}

/* A file name wraps rather than being cut short: it is what tells two rows
   apart, and the shared .prow title would otherwise end it in an ellipsis. */
.set-db-row .p-m > b{
  font-size: 13px;
  white-space: normal;
  overflow-wrap: anywhere;
}

.set-db-row .p-m > span.set-db-row-state{
  margin: var(--s-1) 0 2px;
}

.set-db-row .p-tail > .ic{
  width: 16px;
  height: 16px;
}

.set-db-row .p-m > span.set-db-row-note{
  color: var(--gold-700);
}

.set-db-row-act{
  display: flex;
  justify-content: flex-end;
  gap: var(--s-2);
  padding-inline-end: var(--s-1);
}

/* The change user. */
.set-db-ok{
  display: flex;
  align-items: center;
  gap: var(--s-2);
  margin: 0;
  font-size: 13px;
  font-weight: 600;
  color: var(--green-700);
}

.set-db-ok .ic{
  flex: none;
  width: 16px;
  height: 16px;
  color: var(--green);
}

.set-db-privs{
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
}

.set-db-privg{
  display: flex;
  flex-direction: column;
  gap: var(--s-1);
}

.set-db-chips{
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-1);
  margin: 0;
  padding: 0;
  list-style: none;
}

.set-db-priv{
  font-family: var(--f-mono);
  letter-spacing: .02em;
}

.set-db-priv--miss{
  background: var(--gold-100);
  color: var(--gold-700);
}

.set-db-priv--extra{
  background: var(--red-100);
  color: var(--red-700);
}

/* Why the last Test and save did not save. */
.set-db-result{
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
  padding: var(--s-3) var(--s-4);
  border-left: 3px solid var(--red);
  border-radius: var(--r-sm);
  background: var(--red-100);
}

.set-db-result > b{
  display: flex;
  align-items: center;
  gap: var(--s-2);
  font-size: 13px;
  color: var(--red-700);
}

.set-db-result > b .ic{
  width: 15px;
  height: 15px;
}

.set-db-owner{
  display: flex;
  align-items: center;
  gap: var(--s-2);
  margin: 0;
}

.set-db-owner .ic{
  flex: none;
  width: 14px;
  height: 14px;
}

/* The placeholder the one cached credentials form is mounted into. */
.set-db-slot{
  min-width: 0;
}

.set-db-path{
  overflow-wrap: anywhere;
}

.set-db-warn{
  display: inline-flex;
  align-items: center;
  gap: var(--s-1);
  color: var(--gold-700);
  font-weight: 600;
}

.set-db-warn .ic{
  width: 14px;
  height: 14px;
}

/* Backups and side tables, as resource rows. */
.set-db-res-list{
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.set-db-res{
  align-items: flex-start;
  margin-bottom: 0;
}

.set-db-res .r-body{
  display: flex;
  flex-direction: column;
  gap: var(--s-1);
}

.set-db-res .r-name{
  overflow-wrap: anywhere;
}

.set-db-res .r-act{
  align-self: center;
}

.set-db-mini{
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-1) var(--s-4);
  margin: 0;
}

.set-db-mini > div{
  display: flex;
  gap: var(--s-1);
  min-width: 0;
  font-size: 12px;
}

.set-db-mini dt{
  font-weight: 600;
  color: var(--muted);
}

.set-db-mini dd{
  margin: 0;
  color: var(--ink);
  overflow-wrap: anywhere;
}

/* A notice about the whole tab, above its panels. */
.set-db-msg{
  margin: 0;
  align-items: flex-start;
}

.set-db-msg .ic{
  flex: none;
  margin-top: 2px;
}

.set-db-msg > .btn{
  margin-inline-start: auto;
}

/* One change, in its dialog. */
.set-db-detail{
  display: flex;
  flex-direction: column;
  gap: var(--s-4);
}

.set-db-tech{
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
  padding-top: var(--s-3);
  border-top: 1px solid var(--gray-200);
}

.set-db-detail-sec{
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--s-2);
}

.set-db-detail-sec > pre{
  align-self: stretch;
}

.set-db-lint{
  display: flex;
  flex-direction: column;
  gap: var(--s-1);
  margin: 0;
  padding-inline-start: var(--s-5);
  list-style: disc;
  font-size: 12px;
  line-height: 1.5;
  color: var(--ink);
}

.set-db-code-tag{
  font-family: var(--f-mono);
  letter-spacing: .02em;
}

@media (max-width: 860px){

  /* Contract section 4.5: every tappable control keeps its 44px floor. */
  .set-db-panel .btn,
  .set-db-disc-t,
  .set-db-msg > .btn{
    min-height: 44px;
  }

  .set-db-controls{
    flex-direction: column;
    align-items: stretch;
  }

  .set-db-switch{
    flex: none;
  }

  .set-db-res{
    flex-wrap: wrap;
  }

  .set-db-res .r-act{
    flex: 1 1 100%;
    justify-content: flex-end;
  }
}

@media print{
  .set-db-controls,
  .set-db-card-act,
  .set-db-acts,
  .set-db-row-act,
  .set-db-copy > .btn,
  .set-db-disc-t,
  .set-db-res .r-act,
  .set-db-msg > .btn{
    display: none;
  }

  .set-db-rise{
    animation: none;
  }
}
