/* TagBook design system - the one stylesheet every page shares.
   Identity: the asset tag/label world (docs/ui-redesign-plan.md).
   Tokens below are the only place colors and fonts are defined.
   Mobile (~390px, iOS Safari) is a first-class target: CLAUDE.md rule 9.
   Body text stays at 16px so no input ever triggers iOS focus zoom. */

@font-face {
  font-family: "Barlow";
  font-style: normal;
  font-weight: 400;
  font-display: block;
  src: url(/static/fonts/barlow-400.woff2) format("woff2");
}
@font-face {
  font-family: "Barlow";
  font-style: normal;
  font-weight: 600;
  font-display: block;
  src: url(/static/fonts/barlow-600.woff2) format("woff2");
}
@font-face {
  font-family: "Barlow";
  font-style: normal;
  font-weight: 700;
  font-display: block;
  src: url(/static/fonts/barlow-700.woff2) format("woff2");
}
@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 400;
  font-display: block;
  src: url(/static/fonts/plexmono-400.woff2) format("woff2");
}
@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 600;
  font-display: block;
  src: url(/static/fonts/plexmono-600.woff2) format("woff2");
}
/* Metric-matched stand-ins: while the real font loads, text is laid out
   with the same line heights and, on average, the same widths, so the
   moment it paints nothing moves. From the font files: Barlow's ascent
   1.000 em, descent 0.200, lowercase width 0.476 em against Arial's
   0.482; Plex Mono's width matches Courier New's exactly. */
@font-face {
  font-family: "Barlow Fallback";
  src: local("Arial"), local("Liberation Sans");
  size-adjust: 98.8%;
  ascent-override: 101.2%;
  descent-override: 20.2%;
  line-gap-override: 0%;
}
@font-face {
  font-family: "IBM Plex Mono Fallback";
  src: local("Courier New"), local("Liberation Mono");
  ascent-override: 102.5%;
  descent-override: 27.5%;
  line-gap-override: 0%;
}

:root {
  --ink: #1b2440;      /* text, header bar, primary buttons */
  --muted: #5a6379;
  --ground: #eef0f4;   /* page background */
  --label: #ffffff;    /* panels */
  --line: #d9dde5;
  --tag: #ffc91f;      /* brand yellow: mark, active nav, highlights only */
  --ok: #166534;       /* check-in, in_service */
  --ok-soft: #e6f3ea;
  --out: #1d4ed8;      /* checked out */
  --out-soft: #e8eefc;
  --warn: #92400e;     /* in_repair, warnings */
  --warn-soft: #f8eee1;
  --err: #b91c1c;      /* lost, errors */
  --err-soft: #faeaea;
  /* Building colors (store.BuildingPalette): each a tint and the ink
     that reads on it at 4.5:1 or better (TestBuildingPaletteContrast).
     Hues kept clear of the status colors above, so a building's chip
     never reads as a status. /buildings.css maps each building to one. */
  --b-teal: #005d53;   --b-teal-soft: #b2f0e4;
  --b-plum: #72277a;   --b-plum-soft: #f6d2f9;
  --b-gold: #685300;   --b-gold-soft: #fce5a1;
  --b-sky: #00567b;    --b-sky-soft: #c3e7ff;
  --b-rose: #952345;   --b-rose-soft: #ffd2d9;
  --b-lime: #426100;   --b-lime-soft: #d5efb6;
  --b-violet: #52379f; --b-violet-soft: #ddd9ff;
  --b-sand: #644a2e;   --b-sand-soft: #f0dcc8;
  --b-slate: #414e60;  --b-slate-soft: #d6dde7;
  --b-olive: #515013;  --b-olive-soft: #d8d9b7;
  --b-cyan: #00616c;   --b-cyan-soft: #c7f7fe;
  --b-pink: #902a66;   --b-pink-soft: #ffdeed;
  --sans: "Barlow", "Barlow Fallback", system-ui, -apple-system, "Segoe UI", sans-serif;
  --mono: "IBM Plex Mono", "IBM Plex Mono Fallback", ui-monospace, "SF Mono", Menlo, Consolas, monospace;
}

* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  font-family: var(--sans);
  font-size: 16px;
  line-height: 1.45;
  background: var(--ground);
  color: var(--ink);
}

:focus-visible { outline: 2px solid var(--out); outline-offset: 2px; }

/* --- site header --- */
header.site {
  position: sticky;
  top: 0;
  z-index: 10;
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: .55rem max(1rem, env(safe-area-inset-right)) .55rem max(1rem, env(safe-area-inset-left));
  background: var(--ink);
  color: #fff;
}
.brand {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  color: #fff;
  text-decoration: none;
  font-weight: 700;
  font-size: 1.05rem;
  letter-spacing: .01em;
}
.brand svg { display: block; flex: none; }
header.site > nav {
  display: flex;
  gap: .1rem;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
header.site > nav a {
  color: #c7cddc;
  text-decoration: none;
  font-weight: 600;
  font-size: .95rem;
  padding: .5rem .7rem;
  white-space: nowrap;
}
header.site > nav a:hover { color: #fff; }
header.site > nav a.current { color: #fff; box-shadow: inset 0 -3px 0 var(--tag); }
/* Sign out sits at the far end, out of the nav's scroll so it is never
   the link that scrolls away. */
.signout { margin: 0 0 0 auto; flex: none; }
.signout button {
  background: none;
  border: 0;
  color: #c7cddc;
  font: inherit;
  font-weight: 600;
  font-size: .95rem;
  padding: .5rem .7rem;
  white-space: nowrap;
  cursor: pointer;
}
.signout button:hover { color: #fff; }
/* Touch screens wide enough for the row (desk-side iPads) still get
   44px tap targets; a mouse keeps the compact bar. */
@media (pointer: coarse) {
  header.site > nav a, header.site > .signout button { display: inline-flex; align-items: center; min-height: 44px; }
}
/* Phones and tablets held upright: the links and Sign out fold into a
   menu that drops down under the bar - an admin's ten links need a
   row about 930px wide, so an iPad held upright (820px) clipped Admin
   and Help. */
.sitemenu { display: none; }
/* Where the links fold away, the bar names the page you are on. */
.where { display: none; }
@media (max-width: 960px) {
  header.site > nav, header.site > .signout { display: none; }
  .sitemenu { display: block; margin-left: auto; }
  .where {
    display: block;
    min-width: 0;
    padding-left: 1rem;
    border-left: 1px solid rgba(255, 255, 255, .25);
    font-weight: 600;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
}
/* A phone's bar is narrow: it names the section alone ("Access", not
   "Admin · Access"), a touch smaller, so the sections' names fit beside
   TagBook and Menu at 390 wide; at 375 the longest still ends in an
   ellipsis. Tablets have the room for both. */
@media (max-width: 420px) {
  header.site .where { padding-left: .75rem; font-size: .95rem; }
  header.site .where .wpage { display: none; }
}
.sitemenu > summary {
  display: flex;
  align-items: center;
  gap: .45rem;
  min-height: 44px;
  margin-right: -.5rem;
  padding: 0 .5rem;
  color: #c7cddc;
  font-weight: 600;
  font-size: .95rem;
  list-style: none;
  cursor: pointer;
}
.sitemenu summary::-webkit-details-marker { display: none; }
.sitemenu[open] > summary, .sitemenu > summary:hover { color: #fff; }
.sitemenu .i-close, .sitemenu[open] .i-open { display: none; }
.sitemenu[open] .i-close { display: block; }
.sitemenu nav {
  position: absolute; /* the sticky header is its containing block */
  top: 100%;
  left: 0;
  right: 0;
  max-height: calc(100dvh - 4rem);
  overflow-y: auto;
  padding: .25rem 0 .5rem;
  background: var(--ink);
  border-top: 1px solid rgba(255, 255, 255, .12);
  box-shadow: 0 12px 24px rgba(27, 36, 64, .3);
}
.sitemenu nav a, .sitemenu .signout button {
  display: flex;
  align-items: center;
  width: 100%;
  min-height: 48px;
  padding: 0 max(1rem, env(safe-area-inset-left));
  color: #c7cddc;
  text-decoration: none;
  font-weight: 600;
  font-size: 1.05rem;
}
.sitemenu nav a.current { color: #fff; box-shadow: inset 3px 0 0 var(--tag); }
/* A sectioned page's row (layout.html "menupage"): the caret sits at
   the link's right end and its sections open under the link, indented
   and a step quieter than the pages; the one shown is marked as the
   page is (sectionnav-script). */
.menupage { position: relative; }
.sitemenu .menupage > a { padding-right: 4rem; } /* clears the caret */
.menusections > summary {
  position: absolute;
  top: 0;
  right: max(.5rem, env(safe-area-inset-right));
  display: flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  color: #c7cddc;
  list-style: none;
  cursor: pointer;
}
.menusections > summary:hover, .menusections[open] > summary { color: #fff; }
.menusections[open] > summary svg { transform: rotate(180deg); }
.sitemenu nav .menusections a {
  min-height: 44px;
  padding-left: calc(max(1rem, env(safe-area-inset-left)) + 1.25rem);
  color: #a9b1c6;
  font-size: .95rem;
}
.sitemenu nav .menusections a.current { color: #fff; }
.sitemenu .signout { margin: .25rem 0 0; padding-top: .25rem; border-top: 1px solid rgba(255, 255, 255, .12); }

/* Suggestions under a free-text field (fragments.html "suggest-script"):
   drawn by the page so they stay light, unlike the browser's own. */
.suggest {
  position: absolute;
  z-index: 9; /* under the sticky header */
  margin: 0;
  padding: .25rem;
  list-style: none;
  max-height: 16rem;
  overflow-y: auto;
  background: var(--label);
  border: 1px solid var(--line);
  border-radius: 8px;
  box-shadow: 0 6px 18px rgba(27, 36, 64, .14);
}
.suggest li { min-height: 44px; padding: .65rem .75rem; border-radius: 6px; cursor: pointer; }
.suggest li[aria-selected="true"] { background: var(--ground); }
@media (hover: hover) { .suggest li:hover { background: var(--ground); } }

/* --- layout --- */
main {
  max-width: 960px;
  margin: 1.25rem auto;
  padding: 0 max(1rem, env(safe-area-inset-right)) 0 max(1rem, env(safe-area-inset-left));
}
.panel {
  background: var(--label);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 1rem 1.25rem;
  margin-bottom: 1rem;
}
.panel h2 {
  margin: 0 0 .75rem;
  font-size: 1rem;
  display: flex;
  align-items: center;
  gap: .5rem;
}
.panel .sub { color: var(--muted); font-size: .85rem; margin: -.5rem 0 .75rem; }
.count {
  font-family: var(--mono);
  font-size: .78rem;
  font-weight: 600;
  background: var(--ground);
  border-radius: 999px;
  padding: .05rem .55rem;
  white-space: nowrap; /* "12 of 14000" stays one chip */
}

/* --- site footer: the release that's running, and whose it is --- */
footer.site {
  padding: .25rem 1rem max(1.25rem, env(safe-area-inset-bottom));
  text-align: center;
  font-size: .85rem;
  color: var(--muted);
}
footer.site svg { vertical-align: -2px; margin-right: .15rem; }
footer.site .co { white-space: nowrap; } /* a phone wraps before the name, never inside it */

/* --- sectioned pages (Reports, Admin): left-hand section picker.
   JS (fragments.html "sectionnav-script") shows one panel at a time,
   named by the URL hash; without JS every panel renders and the nav
   degrades to jump links. Phones hide it: the header's Menu lists the
   page's sections under its link (layout.html "menupage"). */
main.sectioned { max-width: 1100px; display: flex; gap: 1.25rem; align-items: flex-start; }
.sectionnav {
  flex: 0 0 10.5rem;
  position: sticky;
  top: 4rem; /* clears the sticky site header */
  display: flex;
  flex-direction: column;
  gap: .15rem;
}
.sectionnav a {
  color: var(--muted);
  text-decoration: none;
  font-weight: 600;
  font-size: .92rem;
  padding: .45rem .7rem;
  border-radius: 8px;
}
.sectionnav a:hover { color: var(--ink); }
.sectionnav a.current {
  background: var(--label);
  color: var(--ink);
  box-shadow: inset 3px 0 0 var(--tag);
}
.sections { flex: 1 1 auto; min-width: 0; }
/* Wide desktops use the width (design rule 9): the column grows so
   report tables keep every column on one line and panels breathe. */
@media (min-width: 1400px) {
  main { max-width: 1360px; }
  main.sectioned { max-width: 1500px; }
}
@media (max-width: 800px) {
  main.sectioned { display: block; }
  .sectionnav { display: none; }
}

/* --- controls (16px minimum everywhere: iOS zooms on smaller inputs) --- */
input[type="text"], input[type="search"], input[type="email"], input[type="number"], input[type="password"], input[type="date"], input[type="file"], select, textarea {
  font: inherit;
  font-size: 16px; /* even inside smaller-font labels - iOS zooms below 16px */
  padding: .5rem .7rem;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--label);
  color: var(--ink);
}
/* Touch screens get 44px tap targets (docs/ui-redesign-plan.md "Mobile
   & iOS"); a mouse keeps the compact controls. */
@media (pointer: coarse) {
  input[type="text"], input[type="search"], input[type="email"], input[type="number"], input[type="password"], input[type="date"], input[type="file"], select, textarea { min-height: 44px; }
}
button.action {
  font: inherit;
  font-weight: 600;
  padding: .55rem 1.25rem;
  min-height: 44px; /* touch target */
  border-radius: 8px;
  border: 1px solid var(--ink);
  background: var(--ink);
  color: #fff;
  cursor: pointer;
}
button.action:hover { background: #2a3557; }
button.action:disabled { opacity: .5; cursor: default; }

/* --- tables --- */
.tablewrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
table { border-collapse: collapse; width: 100%; font-size: .9rem; }
th, td { text-align: left; padding: .45rem .6rem; border-bottom: 1px solid var(--line); }
th {
  color: var(--muted);
  font-size: .72rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .05em;
}
td input { width: 100%; }
/* A sortable report table's header links (report-head, fragments.html;
   the inventory grid's plain building links keep their own look): the
   header's own colour, the whole cell a 44px target, and an arrow on the
   column it is sorted by. */
table.cards th a[hx-get] {
  color: inherit;
  text-decoration: none;
  display: flex;
  align-items: center;
  min-height: 44px;
  margin: -.45rem -.6rem;
  padding: 0 .6rem;
}
table.cards th[aria-sort] a[hx-get]::after { margin-left: .3em; font-size: .7em; color: var(--muted); }
table.cards th[aria-sort="ascending"] a[hx-get]::after { content: "\25B2"; }
table.cards th[aria-sort="descending"] a[hx-get]::after { content: "\25BC"; }
@media (hover: hover) {
  table.cards th a[hx-get]:hover { color: var(--ink); }
}
/* Its sort picker (report-sort) stands in for the header row where a
   phone hides it. */
.sortby { display: none; }
tr.click { cursor: pointer; }
tr.click:active td { background: var(--ground); }
@media (hover: hover) {
  tr.click:hover td { background: var(--ground); }
}
td a { color: var(--out); font-weight: 600; text-decoration: none; }
td a:hover { text-decoration: underline; }

/* identifiers - tags and serials are always monospace */
.mono { font-family: var(--mono); font-size: .92em; }

/* --- status chips: little tags with a punched hole --- */
.badge {
  display: inline-flex;
  align-items: center;
  gap: .38rem;
  font-size: .72rem;
  font-weight: 600;
  letter-spacing: .02em;
  padding: .18rem .6rem .18rem .48rem;
  border-radius: 999px;
  background: var(--ground);
  color: var(--muted);
  white-space: nowrap;
}
.badge::before {
  content: "";
  width: .42em;
  height: .42em;
  border-radius: 50%;
  background: var(--label);
  box-shadow: 0 0 0 1.5px currentColor;
  flex: none;
}
.badge.in_service { background: var(--ok-soft);   color: var(--ok); }
.badge.in_repair  { background: var(--warn-soft); color: var(--warn); }
.badge.retired    { background: var(--ground);    color: var(--muted); }
.badge.lost       { background: var(--err-soft);  color: var(--err); }
.badge.out        { background: var(--out-soft);  color: var(--out); }
.badge.expired    { background: var(--err-soft);  color: var(--err); }
.badge.planned    { background: var(--ground);    color: var(--muted); }

/* --- building chips: a building's name on its color (the "building"
   template func; /buildings.css colors each one by name). Squarer than
   the status chips and without their hole, so the two never read alike,
   and no taller than the text beside it. A name not on the buildings
   list (old data) keeps this uncolored look. A wide desktop keeps the
   name on one line; a narrower screen's squeezed table column wraps it
   inside the chip rather than push the table wider than the page. --- */
.bldg {
  display: inline-block;
  max-width: 100%;
  padding: 0 .4em;
  border-radius: 4px;
  background: var(--ground);
  color: var(--ink);
  font-size: .86em;
  font-weight: 600;
  line-height: 1.45;
  letter-spacing: normal;
  text-transform: none;
  vertical-align: baseline;
}
th .bldg { font-size: .8rem; } /* a header's .72rem caps would shrink it */
@media (min-width: 1400px) { .bldg { white-space: nowrap; } }

.rowbtn {
  font: inherit;
  font-weight: 600;
  font-size: .85rem;
  min-height: 40px;
  padding: .3rem .8rem;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--label);
  color: var(--ink);
  cursor: pointer;
  white-space: nowrap;
}
a.rowbtn { display: inline-flex; align-items: center; text-decoration: none; }
.rowbtn:hover { border-color: var(--ink); }
.rowbtn:disabled { opacity: .5; }
@media (pointer: coarse) { .rowbtn { min-height: 44px; } } /* touch target, as the controls above */

[hidden] { display: none !important; } /* the attribute wins over any display rule */

/* --- the admins' alert strip: a connector failing run after run --- */
.alertstrip {
  background: var(--err-soft);
  color: var(--err);
  border-bottom: 1px solid var(--err);
  padding: .5rem max(1rem, env(safe-area-inset-right)) .5rem max(1rem, env(safe-area-inset-left));
  font-size: .92rem;
}
.alertstrip p { margin: 0 0 .25rem; overflow-wrap: anywhere; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.alertstrip a { color: var(--err); font-weight: 600; }
.muted { color: var(--muted); }
.err   { color: var(--err); }
.warn  { color: var(--warn); }
.ok    { color: var(--ok); }
.empty { color: var(--muted); padding: .75rem 0; }

/* --- responsive tables: opt-in card reflow (cells carry data-th) --- */
@media (max-width: 640px) {
  main { margin-top: 1rem; }
  .panel { padding: .85rem 1rem; }
  table.cards, table.cards tbody { display: block; }
  table.cards thead { display: none; }
  table.cards tbody tr {
    display: block;
    border: 1px solid var(--line);
    border-radius: 10px;
    margin-bottom: .6rem;
    padding: .35rem .85rem;
  }
  /* Label floats left, value flows right. Not flex: a cell's link, badge
     and trailing text would become separate flex items, and an unbreakable
     token (an email) then forces the card wider than the screen. */
  table.cards td {
    display: block;
    text-align: right;
    overflow-wrap: anywhere;
    border-bottom: none;
    padding: .28rem 0;
  }
  table.cards td::before {
    content: attr(data-th);
    float: left;
    margin-right: 1rem;
    color: var(--muted);
    font-family: var(--sans); /* .mono cells must not mono their label */
    font-size: .72rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .05em;
    line-height: 1.8; /* baseline-match the .9rem value text */
  }
  table.cards td:empty { display: none; }
  .sortby {
    display: flex;
    align-items: center;
    gap: .5rem;
    margin: .25rem 0 .5rem;
    font-size: .85rem;
    color: var(--muted);
  }
  .sortby select { flex: 1 1 auto; min-width: 0; font-size: 16px; }
}
/* A table too wide for a tablet either way up (the asset page's tenant
   snapshots: emails, versions and MAC addresses that mustn't break)
   takes the same cards up to 1200px; a desktop gets the table. */
@media (max-width: 1200px) {
  table.cards.wide, table.cards.wide tbody { display: block; }
  table.cards.wide thead { display: none; }
  table.cards.wide tbody tr {
    display: block;
    border: 1px solid var(--line);
    border-radius: 10px;
    margin-bottom: .6rem;
    padding: .35rem .85rem;
  }
  table.cards.wide td {
    display: block;
    text-align: right;
    overflow-wrap: anywhere;
    border-bottom: none;
    padding: .28rem 0;
  }
  table.cards.wide td::before {
    content: attr(data-th);
    float: left;
    margin-right: 1rem;
    color: var(--muted);
    font-family: var(--sans);
    font-size: .72rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .05em;
    line-height: 1.8;
  }
  table.cards.wide td:empty { display: none; }
}

/* --- a paged report's controls (fragments.html report-toolbar and the
   templates after it; docs/reports-filter-plan.md): the search with
   Filter and Sort beside it, the filters that are on as chips, the
   fields as a row under the toolbar, the sorts as a menu under their
   button, and the pager under the table. A phone (below) takes the
   fields and the sorts as sheets from the bottom and Load more for the
   pages. --- */
.rtools { position: relative; display: flex; flex-wrap: wrap; align-items: center; gap: .5rem; margin-bottom: .6rem; }
.rsearch { position: relative; display: flex; align-items: center; flex: 1 1 12rem; min-width: 0; }
.rsearch svg { position: absolute; left: .75rem; color: var(--muted); pointer-events: none; }
.rsearch input { width: 100%; min-height: 44px; padding-left: 2.25rem; }
.rtool {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .45rem;
  min-height: 44px; /* touch target, and the search box's height */
  padding: 0 1rem;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--label);
  color: var(--ink);
  font: inherit;
  font-weight: 600;
  font-size: .95rem;
  white-space: nowrap;
  cursor: pointer;
}
.rtool[aria-expanded="true"] { background: var(--ink); border-color: var(--ink); color: #fff; }
@media (hover: hover) { .rtool:not([aria-expanded="true"]):hover { border-color: var(--ink); } }
/* How many filters are on: ink on the brand yellow, never yellow text. */
.rnum {
  min-width: 1.4rem;
  padding: 0 .4rem;
  border-radius: 999px;
  background: var(--tag);
  color: var(--ink);
  font-size: .78rem;
  font-weight: 700;
  text-align: center;
}
.rlink {
  min-height: 32px;
  padding: 0 .25rem;
  border: 0;
  background: none;
  color: var(--muted);
  font: inherit;
  font-size: .85rem;
  text-decoration: underline;
  cursor: pointer;
}
.rchips { display: flex; flex-wrap: wrap; align-items: center; gap: .4rem; margin-bottom: .6rem; }
.rchip {
  display: inline-flex;
  align-items: center;
  gap: .3em; /* "Building:" and its value, which a flex item's trailing space can't part */
  max-width: 100%;
  padding-left: .75rem;
  border-radius: 999px;
  background: var(--out-soft);
  color: var(--out);
  font-size: .85rem;
  font-weight: 600;
  overflow-wrap: anywhere;
}
.rchip button {
  flex: none;
  min-width: 32px;
  min-height: 32px;
  border: 0;
  border-radius: 999px;
  background: none;
  color: inherit;
  font: inherit;
  font-size: 1rem;
  cursor: pointer;
}
@media (pointer: coarse) { .rchip button, .rlink { min-width: 44px; min-height: 44px; } }

/* The filter's fields: a row of them under the toolbar, Reset and
   Apply at its end; a building list scrolls in its box. */
.rfilters { margin-bottom: .75rem; padding: .85rem 1rem; background: var(--ground); border: 1px solid var(--line); border-radius: 10px; }
.rsheethead { display: none; }
.rfields { display: grid; grid-template-columns: repeat(auto-fill, minmax(12rem, 1fr)); gap: .75rem 1rem; align-items: end; }
.rfield { display: flex; flex-direction: column; gap: .3rem; min-width: 0; margin: 0; padding: 0; border: 0; color: var(--muted); font-size: .85rem; font-weight: 600; }
.rfield select, .rfield input[type="date"] { width: 100%; min-width: 0; }
.rdays { display: flex; align-items: center; gap: .5rem; font-weight: 400; }
.rdays input { width: 6.5rem; }
.rflag { flex-direction: row; align-items: center; gap: .55rem; min-height: 44px; color: var(--ink); font-size: .95rem; font-weight: 400; }
.rflag input, .rticks input { flex: none; width: 1.2rem; height: 1.2rem; margin: 0; accent-color: var(--ink); }
.rmulti { grid-row: span 2; align-self: stretch; }
.rmulti legend { padding: 0; margin-bottom: .3rem; }
.rticks { display: flex; flex-direction: column; max-height: 11.5rem; overflow-y: auto; padding: .2rem .7rem; border: 1px solid var(--line); border-radius: 8px; background: var(--label); }
.rticks label { display: flex; align-items: center; gap: .55rem; min-height: 36px; color: var(--ink); font-size: .95rem; font-weight: 400; }
.rfilteracts { display: flex; justify-content: flex-end; gap: .5rem; margin-top: .75rem; }
.rnarrow { display: none; }
@media (pointer: coarse) { .rticks label { min-height: 44px; } }

/* The sorts: a menu under the Sort button, the current one filled. */
.rsorts {
  position: absolute;
  z-index: 5; /* over the table, under the sticky header */
  top: calc(100% + 6px);
  right: 0;
  width: min(22rem, 100%);
  padding: .6rem;
  background: var(--label);
  border: 1px solid var(--line);
  border-radius: 10px;
  box-shadow: 0 6px 18px rgba(27, 36, 64, .14);
}
.rsorts h3 { margin: .1rem .25rem .2rem; font-size: 1rem; }
.rsorts p { margin: 0 .25rem .5rem; font-size: .85rem; }
.rsortopt {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  width: 100%;
  min-height: 44px;
  margin-top: .35rem;
  padding: 0 .85rem;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--label);
  color: var(--ink);
  font: inherit;
  font-weight: 600;
  text-align: left;
  cursor: pointer;
}
.rsortopt span { color: var(--muted); font-size: .85rem; font-weight: 400; white-space: nowrap; }
.rsortopt.current, .rsortopt.current span { background: var(--ink); border-color: var(--ink); color: #fff; }
@media (hover: hover) { .rsortopt:not(.current):hover { border-color: var(--ink); } }

/* The pager: where the page sits, the rows a page, the pages. */
.rpager { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem 1rem; margin-top: .75rem; font-size: .9rem; }
.rper { display: flex; align-items: center; gap: .5rem; margin-left: auto; color: var(--muted); }
.rpages { display: flex; flex-wrap: wrap; align-items: center; gap: .35rem; }
.rpages .rowbtn { min-width: 40px; justify-content: center; }
.rpages .rowbtn.current { background: var(--ink); border-color: var(--ink); color: #fff; }
.rbackdrop, .rsorted, .rmore { display: none; }

/* A phone: the search on its own line over Filter and Sort, the chips
   their values alone, the fields and the sorts as sheets from the
   bottom over a backdrop, the sort said over the cards, and Load more
   instead of the pages. */
@media (max-width: 640px) {
  .rsearch { flex-basis: 100%; }
  .rtool { flex: 1 1 0; }
  .rwhat, .rchipname, .rwide, .rpager { display: none; }
  .rnarrow { display: inline; }
  .rpanel {
    position: fixed;
    z-index: 30; /* over the sticky header */
    top: auto;
    left: 0;
    right: 0;
    bottom: 0;
    width: auto;
    max-height: 85dvh;
    overflow-y: auto;
    overscroll-behavior: contain;
    margin: 0;
    padding: .5rem max(1rem, env(safe-area-inset-right)) max(1rem, env(safe-area-inset-bottom)) max(1rem, env(safe-area-inset-left));
    background: var(--label);
    border: 0;
    border-radius: 16px 16px 0 0;
    box-shadow: 0 -8px 24px rgba(27, 36, 64, .2);
  }
  .rpanel::before { content: ""; display: block; width: 2.5rem; height: 4px; margin: 0 auto .6rem; border-radius: 2px; background: var(--line); } /* the sheet's grab bar */
  .rsorts h3 { margin: 0 0 .2rem; font-size: 1.1rem; }
  .rsorts p { margin: 0 0 .4rem; }
  .rsheethead { display: flex; align-items: center; justify-content: space-between; margin-bottom: .5rem; }
  .rsheethead h3 { margin: 0; font-size: 1.1rem; }
  .rfields { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .75rem; }
  .rmulti { grid-column: 1 / -1; grid-row: auto; }
  .rticks { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); max-height: none; overflow: visible; column-gap: .75rem; }
  .rfilteracts .rowbtn { display: none; } /* the sheet's own Reset is at its head */
  .rfilteracts .action { width: 100%; }
  .rbackdrop { position: fixed; inset: 0; z-index: 29; background: rgba(27, 36, 64, .45); }
  .rform:has(.rpanel:not([hidden])) .rbackdrop { display: block; }
  .rsorted { display: block; margin: 0 0 .5rem; font-size: .85rem; }
  .rmore { display: block; margin-top: .25rem; }
  .rmore .rowbtn { width: 100%; justify-content: center; }
}

/* --- tickets (docs/tickets-plan.md): the queue and one ticket. The
   page uses the width from a landscape iPad up: the queue's table
   fills it, a ticket runs in two columns. --- */
main.tickets { max-width: 1360px; }
@media (min-width: 1400px) { main.tickets { max-width: 1600px; } }
.tqbar { display: flex; align-items: center; gap: .75rem; }
.tqbar input[type="search"] { width: 100%; min-width: 0; }
.tqbar .rowbtn { flex: none; min-height: 44px; }

/* The view chips: the current one filled, a device filter in its own
   color with its x to take it off. A phone scrolls them in one row. */
.tchips { display: flex; flex-wrap: wrap; gap: .4rem; margin-bottom: .75rem; }
.tchips a {
  display: inline-flex;
  align-items: center;
  min-height: 40px;
  padding: .3rem .85rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--label);
  color: var(--ink);
  font-weight: 600;
  font-size: .9rem;
  text-decoration: none;
  white-space: nowrap;
}
.tchips a.current { background: var(--ink); border-color: var(--ink); color: #fff; }
.tchips a.tdevchip { gap: .35rem; background: var(--out-soft); border-color: var(--out-soft); color: var(--out); }
@media (pointer: coarse) { .tchips a { min-height: 44px; } }
@media (hover: hover) { .tchips a:not(.current):hover { border-color: var(--ink); } }

/* The queue: one line a ticket from a tablet up. The header cells
   take their widths (table-layout: fixed), the subject the rest; each
   can be dragged wider or narrower by its corner, the widths kept by
   this browser (tickets.html). A long cell is cut short, its whole
   text in its title. */
table.tq { table-layout: fixed; }
table.tq th { resize: horizontal; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; padding: .45rem .5rem; }
table.tq td { height: 2.75rem; padding: 0 .5rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
table.tq td.c-subject a { color: var(--ink); }
table.tq td .badge, table.tq td .bldg { display: inline-block; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; vertical-align: middle; }
table.tq td .badge::before { display: inline-block; margin-right: .38rem; vertical-align: .05em; }
table.tq td.c-subject .badge { max-width: 50%; margin-right: .25rem; }
table.tq .via { color: var(--muted); }
table.tq th.c-num { width: 4rem; }
table.tq th.c-requester { width: 9rem; }
table.tq th.c-device { width: 6.5rem; }
table.tq th.c-building { width: 8.5rem; }
table.tq th.c-status { width: 10.75rem; }
table.tq th.c-assigned { width: 6.5rem; }
table.tq th.c-updated { width: 8.75rem; }
/* Below a wide desktop, Requester responded is its dot alone, the
   words in its title, so the subject keeps the room. */
@media (min-width: 641px) and (max-width: 1399px) {
  table.tq td.c-subject .badge.responded { font-size: 0; padding: .32rem; gap: 0; vertical-align: -.1rem; }
  table.tq td.c-subject .badge.responded::before { width: .5rem; height: .5rem; margin: 0; }
}
@media (min-width: 1400px) {
  table.tq th.c-requester { width: 12rem; }
  table.tq th.c-building { width: 10rem; }
  table.tq th.c-status { width: 11.5rem; }
  table.tq th.c-assigned { width: 8rem; }
  table.tq th.c-updated { width: 11rem; }
}
/* An upright iPad keeps one line by leaving out who it is assigned to
   and how the last message came; the ticket shows both. */
@media (min-width: 641px) and (max-width: 960px) {
  #tickets-region { padding-left: .75rem; padding-right: .75rem; }
  table.tq .c-assigned, table.tq .via { display: none; }
  table.tq th.c-num { width: 3.25rem; }
  table.tq th.c-requester { width: 7rem; }
  table.tq th.c-device { width: 5.5rem; }
  table.tq th.c-building { width: 6.5rem; }
  table.tq th.c-status { width: 7.5rem; }
  table.tq th.c-updated { width: 5.75rem; }
}
/* A phone: the cards, each headed by its number and its subject in
   full. */
@media (max-width: 640px) {
  /* Every view in sight, wrapped onto rows, never scrolled sideways. */
  .tchips { gap: .35rem; }
  .tchips a { padding: .3rem .7rem; font-size: .85rem; }
  table.cards.tq td { height: auto; padding: .28rem 0; white-space: normal; overflow: visible; }
  table.cards.tq td .badge, table.cards.tq td .bldg { white-space: normal; }
  table.cards.tq td.c-num, table.cards.tq td.c-subject { text-align: left; }
  table.cards.tq td.c-num::before, table.cards.tq td.c-subject::before { content: none; }
  table.cards.tq td.c-num { padding-bottom: 0; }
  table.cards.tq td.c-subject { padding-top: 0; font-size: 1rem; }
  table.cards.tq td.c-subject .badge { max-width: none; }
}

/* The ticket's statuses, Requester responded, and the note label. */
.badge.t-new     { background: var(--out-soft);  color: var(--out); }
.badge.t-open    { background: var(--warn-soft); color: var(--warn); }
.badge.t-pending { background: var(--ground);    color: var(--muted); }
.badge.t-closed  { background: var(--ok-soft);   color: var(--ok); }
.badge.responded { background: var(--tag);       color: var(--ink); }
.badge.tnote     { background: var(--label);     color: var(--warn); }

/* One ticket: the head across the top; the thread and the composer on
   the left, the fields and the cards on the right, from a landscape
   iPad up. Narrower, one column in the page's order. */
.tback { display: inline-block; color: var(--out); font-weight: 600; text-decoration: none; margin-bottom: .75rem; min-height: 44px; line-height: 44px; margin-top: -.5rem; }
.tgrid { display: grid; grid-template-columns: minmax(0, 1fr); }
.tgrid > * { min-width: 0; }
@media (min-width: 961px) {
  .tgrid { grid-template-columns: minmax(0, 1fr) 22rem; grid-template-rows: auto auto 1fr; column-gap: 1rem; }
  .tgrid .thead { grid-column: 1 / -1; }
  .tgrid .tconv { grid-column: 1; grid-row: 2 / span 2; }
  .tgrid .tside { grid-column: 2; grid-row: 2; align-self: start; }
  .tgrid .tcards { grid-column: 2; grid-row: 3; align-self: start; }
}
@media (min-width: 1400px) { .tgrid { grid-template-columns: minmax(0, 1fr) 26rem; } }
@media (min-width: 641px) and (max-width: 960px) {
  .tcards { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: 1rem; align-items: start; }
}
.thead h1 { margin: 0 0 .4rem; font-size: 1.3rem; line-height: 1.25; overflow-wrap: anywhere; }
.thead .tnum { color: var(--muted); font-weight: 600; }
.tmeta { display: flex; flex-wrap: wrap; align-items: center; gap: .35rem .6rem; font-size: .9rem; }
.tline { margin: 0 0 .75rem; overflow-wrap: anywhere; }

/* The side panel: a <details> whose summary is its heading. */
.tside > summary {
  display: flex;
  align-items: center;
  min-height: 44px;
  margin: -.6rem 0;
  font-weight: 700;
  cursor: pointer;
  list-style: none;
}
.tside > summary::-webkit-details-marker { display: none; }
.tside > summary::after { content: "\25BE"; margin-left: auto; color: var(--muted); }
.tside:not([open]) > summary::after { content: "\25B8"; }
.tside[open] > summary { margin-bottom: .4rem; }
.tform { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr)); gap: .75rem 1rem; align-items: end; }
.tform > label:first-child { grid-column: 1 / -1; }
.tform label, .tattach, .tccbox .tother, .tnewcol > label {
  display: flex;
  flex-direction: column;
  gap: .3rem;
  font-size: .78rem;
  font-weight: 600;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: .05em;
}
.tform input, .tform select, .tattach input, .tccbox .tother input, .tnewcol > label > * { width: 100%; min-width: 0; }
.tform button { justify-self: start; }
.tpair { display: flex; flex-direction: column; gap: .75rem; }
/* A pending ticket's optional date shows once Pending is picked. */
.tform .tsched { display: none; }
.tpair:has(option[value="pending"]:checked) .tsched { display: flex; }
/* The device in the panel: the New ticket form's box, across the form. */
.tform .tdevpick { grid-column: 1 / -1; margin: 0; }
.thistory { margin-top: 1rem; border-top: 1px solid var(--line); }
.thistory > summary { display: flex; align-items: center; gap: .5rem; min-height: 44px; font-weight: 600; font-size: .9rem; cursor: pointer; }
.thistory ul { list-style: none; margin: 0; padding: 0; font-size: .85rem; }
.thistory li { padding: .35rem 0; border-top: 1px solid var(--line); overflow-wrap: anywhere; }

/* The thread: a body is text with its line breaks; an internal note is
   shaded and labelled so it never reads as a reply. */
.tmsg { padding: .85rem 0; border-top: 1px solid var(--line); }
.tthread h2 + .tmsg { border-top: 0; padding-top: 0; }
.tmsg.internal { margin: .5rem 0; padding: .75rem .85rem; border: 1px solid var(--warn-soft); border-radius: 8px; background: var(--warn-soft); }
.tmsg.internal + .tmsg { border-top: 0; }
.tmsghead { display: flex; flex-wrap: wrap; align-items: center; gap: .2rem .5rem; margin-bottom: .35rem; overflow-wrap: anywhere; }
.tmsghead .muted { font-size: .85rem; }
.tbody { white-space: pre-wrap; overflow-wrap: anywhere; max-width: 80ch; }
.tccline { margin: .45rem 0 0; font-size: .85rem; overflow-wrap: anywhere; }
.tfiles { list-style: none; margin: .5rem 0 0; padding: 0; display: flex; flex-wrap: wrap; gap: .25rem 1.25rem; }
.tfiles li { display: flex; align-items: center; gap: .55rem; min-height: 44px; min-width: 0; overflow-wrap: anywhere; font-size: .9rem; }
.tfiles a { display: inline-flex; align-items: center; min-height: 44px; color: var(--out); font-weight: 600; text-decoration: none; }
.tthumb img { display: block; width: 72px; height: 72px; object-fit: cover; border-radius: 6px; border: 1px solid var(--line); background: var(--ground); }

/* The composer: closed, a start bar - the last send's line, Reply and
   Internal note; open, Reply or Internal note as tabs - a note shaded
   as the thread shades one - the CC folded out, and Cancel at the
   row's start with Send at its far end. */
.tstart { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem .75rem; }
.tstart .tline { flex: 0 0 100%; margin: 0; }
.tstart .rowbtn, .tsend .rowbtn { min-height: 44px; }
.tcomposer.internal { background: var(--warn-soft); border-color: var(--warn-soft); }
.tmodes { display: flex; gap: .25rem; margin: -.5rem 0 .75rem; border-bottom: 1px solid var(--line); }
.tmodes a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0 .9rem;
  margin-bottom: -1px;
  border-bottom: 3px solid transparent;
  color: var(--muted);
  font-weight: 600;
  text-decoration: none;
}
.tmodes a.current { color: var(--ink); border-bottom-color: var(--tag); }
@media (hover: hover) { .tmodes a:not(.current):hover { color: var(--ink); } }
#composer-form { display: flex; flex-direction: column; gap: .75rem; }
.tcanned { align-self: flex-start; max-width: 100%; }
#composer-body { width: 100%; min-height: 10rem; resize: vertical; }
.tcc > summary { display: inline-flex; align-items: center; min-height: 44px; font-weight: 600; cursor: pointer; }
.tccbox { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 16rem), 1fr)); gap: 0 1rem; }
.tccbox label { display: flex; align-items: center; gap: .55rem; min-height: 44px; min-width: 0; }
.tccbox label > span { min-width: 0; overflow-wrap: anywhere; }
.tccbox input[type="checkbox"] { width: 22px; height: 22px; margin: 0; flex: none; }
.tccbox .tother { grid-column: 1 / -1; align-items: stretch; margin-top: .25rem; }
.tsend { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: .5rem .75rem; }
/* Send is a split button: its caret floats "send and set as" up from it
   as a card, Freshservice's way - a full-width line per status, anchored
   to the button's right edge, which is the screen's on a phone, so the
   card never runs off it. */
.tsplit { display: flex; position: relative; }
.tsplit .action { border-radius: 8px 0 0 8px; }
.tsendas > summary {
  display: flex;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
  width: 44px;
  height: 100%;
  min-height: 44px;
  border: 1px solid var(--ink);
  border-left-color: rgba(255, 255, 255, .35); /* the divider between the halves */
  border-radius: 0 8px 8px 0;
  background: var(--ink);
  color: #fff;
  cursor: pointer;
  list-style: none;
}
.tsendas > summary::-webkit-details-marker { display: none; }
.tsendas > summary::after { content: "\25BE"; }
.tsendas[open] > summary::after { content: "\25B4"; }
@media (hover: hover) { .tsendas > summary:hover { background: #2a3557; } }
.tsendmenu {
  display: none;
  position: absolute;
  z-index: 9; /* over the composer, under the sticky header */
  bottom: calc(100% + 6px);
  right: 0;
  flex-direction: column;
  box-sizing: border-box;
  min-width: 15rem;
  max-width: calc(100vw - 32px);
  padding: .25rem;
  background: var(--label);
  border: 1px solid var(--line);
  border-radius: 8px;
  box-shadow: 0 6px 18px rgba(27, 36, 64, .14);
}
.tsplit:has(.tsendas[open]) .tsendmenu { display: flex; }
.tsendmenu button {
  display: flex;
  align-items: center;
  width: 100%;
  min-height: 44px;
  padding: 0 .75rem;
  border: 0;
  border-radius: 6px;
  background: none;
  color: var(--ink);
  font: inherit;
  text-align: left;
  white-space: nowrap;
  cursor: pointer;
}
.tsendmenu button:active { background: var(--ground); }
@media (hover: hover) { .tsendmenu button:hover { background: var(--ground); } }

/* The requester and device cards. */
.tcard h3 { margin: .9rem 0 .35rem; font-size: .72rem; font-weight: 600; text-transform: uppercase; letter-spacing: .05em; color: var(--muted); }
.twho { display: flex; flex-direction: column; gap: .15rem; overflow-wrap: anywhere; }
.twho a, .touts a, .tfacts a { color: var(--out); font-weight: 600; text-decoration: none; }
.touts { list-style: none; margin: 0; padding: 0; }
.touts li { padding: .45rem 0; border-top: 1px solid var(--line); overflow-wrap: anywhere; }
.touts li:first-child { border-top: 0; }
.ttag { font-size: 1.2rem; font-weight: 600; overflow-wrap: anywhere; }
.tfacts { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: .4rem .85rem; margin: .75rem 0; }
.tfacts dt { color: var(--muted); font-size: .72rem; font-weight: 600; text-transform: uppercase; letter-spacing: .05em; line-height: 1.8; }
.tfacts dd { margin: 0; overflow-wrap: anywhere; }
.touts .muted, .tfacts .muted { white-space: nowrap; } /* a date never breaks */
.tdesk { margin-top: .75rem; }

/* The asset page's Tickets line: the count, New ticket beside it. */
.tassetline { display: flex; flex-wrap: wrap; align-items: center; gap: .35rem .75rem; margin-top: .5rem; }
.tassetline > a:not(.rowbtn) { display: inline-flex; align-items: center; min-height: 44px; color: var(--out); font-weight: 600; text-decoration: none; }
.tassetline .rowbtn { min-height: 44px; }

/* New ticket: one column on a phone and an upright iPad; from a
   landscape iPad up, the requester, the device and what it is about
   down the left, the description and its options down the right. */
.tnew h1 { margin: 0 0 .75rem; font-size: 1.3rem; }
.tnewgrid { display: grid; grid-template-columns: minmax(0, 1fr); }
.tnewgrid > * { min-width: 0; }
@media (min-width: 961px) {
  .tnewgrid { grid-template-columns: repeat(2, minmax(0, 1fr)); grid-template-rows: auto 1fr; column-gap: 1rem; align-items: start; }
  .tnewgrid .tnewwho { grid-column: 1; grid-row: 1; }
  .tnewgrid .tnewwhat { grid-column: 1; grid-row: 2; }
  .tnewgrid .tnewmsg { grid-column: 2; grid-row: 1 / span 2; }
}
@media (min-width: 1400px) { .tnewgrid { grid-template-columns: minmax(0, 5fr) minmax(0, 6fr); } }
.tnewwho input[type="search"] { width: 100%; }
.tpicked { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: .5rem 1rem; }
.tpicked .twho { min-width: 0; }
.tpicked .rowbtn { min-height: 44px; }
/* The search's matches: each a row to tap, the name first. */
.tpeople { margin-top: .35rem; }
.tperson {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .1rem .5rem;
  min-height: 44px;
  padding: .45rem .5rem;
  border-bottom: 1px solid var(--line);
  color: var(--ink);
  text-decoration: none;
  overflow-wrap: anywhere;
}
.tperson .muted { font-size: .85rem; }
.tperson:active { background: var(--ground); }
@media (hover: hover) { .tperson:hover { background: var(--ground); } }
.tperson.tadd { color: var(--out); border-bottom: 0; }
.tnewperson { margin-bottom: .5rem; }
.tsearchagain { display: inline-flex; align-items: center; min-height: 44px; }
/* The form's fold-outs say they fold, a marker before each. */
.tnewmsg .tcc > summary::before { content: "\25B8"; margin-right: .45rem; color: var(--muted); }
.tnewmsg .tcc[open] > summary::before { content: "\25BE"; }
/* Category and Building side by side where there is room. */
.tnewwhat .tform { grid-template-columns: repeat(auto-fit, minmax(min(100%, 12rem), 1fr)); }
/* The device: one optional box, the requester's checkouts below it to
   tap in. */
.tdevpick { min-width: 0; margin: 1.25rem 0 0; }
.tdevpick > label { display: flex; flex-direction: column; gap: .3rem; font-size: .78rem; font-weight: 600; color: var(--muted); text-transform: uppercase; letter-spacing: .05em; }
.tdevpick > label input { width: 100%; min-width: 0; }
.toptional { text-transform: none; letter-spacing: 0; font-weight: 400; }
.tdevfill { display: flex; flex-wrap: wrap; align-items: center; gap: .4rem; margin-top: .5rem; }
.tdevfill .muted { flex: 0 0 100%; font-size: .85rem; }
.tdevfill .rowbtn { min-height: 44px; overflow-wrap: anywhere; text-align: left; }
.tnewcol { display: flex; flex-direction: column; gap: .75rem; }
.tnewcol textarea { min-height: 10rem; resize: vertical; }
.tnewcol .action { align-self: flex-start; }

/* --- Request help (docs/tickets-plan.md "Screens"): the requester's
   side, phone first. The form and their requests stack on a phone and
   an upright iPad; from a landscape iPad up the requests sit beside the
   form. One request reuses the ticket's head and thread, its reply form
   beside the thread from a landscape iPad up. --- */
main.request { max-width: 1360px; }
.request h1 { margin: 0 0 .75rem; font-size: 1.3rem; line-height: 1.25; }
.rqgrid, .rqconv { display: grid; grid-template-columns: minmax(0, 1fr); }
.rqgrid > *, .rqconv > * { min-width: 0; }
@media (min-width: 961px) {
  .rqgrid { grid-template-columns: minmax(0, 3fr) minmax(0, 2fr); column-gap: 1rem; align-items: start; }
  .rqconv { grid-template-columns: minmax(0, 1fr) 24rem; column-gap: 1rem; align-items: start; }
}
@media (min-width: 1400px) { .rqconv { grid-template-columns: minmax(0, 1fr) 28rem; } }
.rqform { display: flex; flex-direction: column; gap: 1.1rem; }
.rqform h1, .rqform .tline { margin: 0; }
.rqpick { min-width: 0; margin: 0; padding: 0; border: 0; }
.rqpick legend { padding: 0; margin-bottom: .45rem; font-weight: 700; }
.rqpick legend .muted { font-weight: 400; font-size: .9rem; }
/* Which device: each checkout a card to tap, the one picked outlined. */
.rqdevices { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 15rem), 1fr)); gap: .6rem; }
.rqdevice { display: flex; align-items: center; gap: .75rem; min-height: 64px; padding: .7rem .9rem; border: 2px solid var(--line); border-radius: 10px; background: var(--label); cursor: pointer; overflow-wrap: anywhere; }
.rqdevice input { width: 22px; height: 22px; margin: 0; flex: none; accent-color: var(--out); }
.rqdevice > span { display: flex; flex-direction: column; min-width: 0; }
.rqdevice .rqtag { font-weight: 700; }
.rqdevice .muted { font-size: .85rem; }
.rqdevice:has(input:checked) { border-color: var(--out); background: var(--out-soft); }
/* What's wrong: the categories as chips, one picked or none. */
.rqchips { display: flex; flex-wrap: wrap; gap: .45rem; }
.rqchip { position: relative; display: inline-flex; }
.rqchip input { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: pointer; }
.rqchip span { display: inline-flex; align-items: center; min-height: 44px; padding: .3rem 1rem; border: 1px solid var(--line); border-radius: 999px; background: var(--label); font-weight: 600; font-size: .95rem; }
.rqchip input:checked + span { background: var(--ink); border-color: var(--ink); color: #fff; }
.rqchip input:focus-visible + span { outline: 2px solid var(--out); outline-offset: 2px; }
@media (hover: hover) { .rqchip input:not(:checked):hover + span { border-color: var(--ink); } }
.rqfield { display: flex; flex-direction: column; gap: .35rem; font-weight: 700; }
.rqfield textarea, .rqreplyform textarea { width: 100%; min-height: 8rem; resize: vertical; font-weight: 400; }
.rqfield input[type="file"] { width: 100%; min-width: 0; min-height: 44px; font-weight: 400; }
.rqform .action, .rqreplyform .action { align-self: stretch; }
@media (min-width: 641px) { .rqform .action, .rqreplyform .action { align-self: flex-start; min-width: 10rem; } }
/* Your requests: a row to tap each, the number and subject first. */
.rqmine h3 { margin: 1rem 0 .35rem; font-size: .72rem; font-weight: 600; text-transform: uppercase; letter-spacing: .05em; color: var(--muted); }
.rqlist { list-style: none; margin: 0; padding: 0; }
.rqlist li { border-top: 1px solid var(--line); }
.rqlist li:first-child { border-top: 0; }
.rqlist a { display: flex; flex-direction: column; gap: .3rem; min-height: 44px; padding: .65rem .35rem; color: var(--ink); text-decoration: none; overflow-wrap: anywhere; }
.rqlist a:active { background: var(--ground); }
@media (hover: hover) { .rqlist a:hover { background: var(--ground); } }
.rqtop strong { font-weight: 600; }
.rqmeta { display: flex; flex-wrap: wrap; align-items: center; gap: .25rem .6rem; font-size: .88rem; }
.rqmeta .muted { white-space: nowrap; } /* a date never breaks */
.rqsent { background: var(--ok-soft); border-color: var(--ok); color: var(--ok); overflow-wrap: anywhere; }
.rqsent p { margin: .4rem 0 0; }
.rqreply .tline a { color: inherit; font-weight: 600; }
.rqreplyform { display: flex; flex-direction: column; gap: .75rem; }
