/* GERT. Light, bright, Arabic first.
 *
 * Everything directional uses LOGICAL properties (inline-start, padding-inline)
 * so one stylesheet serves both directions. There is no [dir="rtl"] override
 * block, on purpose: a second block is a second place to forget.
 *
 * Colour rule carried from the handover app, and it is load bearing:
 * AMBER ONLY EVER MEANS ATTENTION. It is never used for branding, never for a
 * normal state, never for decoration. If a treatment means "look at this"
 * anywhere, it cannot also mean "this is fine" somewhere else. Brand is blue.
 *
 * No external requests of any kind. No CDN fonts, no icon sets. The system
 * font stack renders Arabic properly on every platform the coordinators use,
 * and a webfont that fails to load on a phone in a corridor is worse than one
 * that was never asked for.
 */

:root {
  --ink:        #16202e;
  --ink-soft:   #55637a;
  --ink-faint:  #8b97ab;

  /* MEASURED, not chosen: this is the exact colour bg-app.jpg fades to at its
     bottom edge, sampled by bin/make_brand.php. The band and the flat page
     colour have to be the same value or there is a visible horizontal seam
     across every page. If the artwork is ever regenerated, re-run that script
     and paste the value it prints. */
  --bg:         #faf9f5;
  --surface:    #ffffff;
  --line:       #dfe6f0;
  --line-soft:  #edf1f7;

  /* Form fields get their own two tokens rather than borrowing --line. An
     input has to carry more contrast than a card edge does: a card is found by
     its content, a field has to be findable when it holds nothing at all.
   *
     --field-line is MEASURED against white, not picked by eye. WCAG 1.4.11
     wants 3:1 for the boundary of a user interface component, and the first
     attempt at this managed 1.56:1, which is how an empty form ended up
     looking like a blank card. This value measures 3.1:1. */
  --field:      #eff4fa;
  --field-line: #7e93b0;

  --brand:      #1263c4;
  --brand-dark: #0d4b96;
  --brand-tint: #e8f1fd;

  --ok:         #17794a;
  --ok-tint:    #e5f5ec;
  --warn:       #a55a00;
  --warn-tint:  #fdf1de;
  --danger:     #b3261e;
  --danger-tint:#fdeceb;

  --radius:     14px;
  --radius-sm:  9px;
  --shadow:     0 1px 2px rgba(22, 32, 46, .05), 0 8px 24px rgba(22, 32, 46, .06);
  --shadow-sm:  0 1px 2px rgba(22, 32, 46, .06);

  --touch:      48px;
}

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  /* The artwork is a BAND across the top at full width and natural height, with
     the flat page colour continuing beneath it. Deliberately not `cover`:
     cover would crop the composition differently at every window size, and on
     a phone would show one meaningless corner of it blown up. This way the art
     is always the whole picture, just shorter on a narrow screen. */
  background-color: var(--bg);
  background-image: url("/assets/img/bg-app.jpg");
  background-repeat: no-repeat;
  background-position: top center;
  background-size: 100% auto;
  color: var(--ink);
  font-family: "Segoe UI", system-ui, -apple-system, "Noto Naskh Arabic",
               "Noto Sans Arabic", Tahoma, Arial, sans-serif;
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

/* Latin-only values: serials, employee numbers, phone numbers. These must read
   left to right even inside an Arabic sentence, or they cannot be compared
   against the label on the device.
 *
 * DIRECTION AND ALIGNMENT ARE TWO DIFFERENT THINGS, and conflating them cost a
 * real bug report. `.mono` used to set `direction: ltr`. On an inline span that
 * is harmless, but on a BLOCK it also redefines `text-align: start` to mean
 * LEFT, so in an Arabic page the number was flung to the far side of its card:
 * measured at 217px from the reading edge while its own label sat at 19px. The
 * owner reported the count as missing, and he was right to, because nothing was
 * where a number should be.
 *
 * `unicode-bidi: isolate` alone does the job that was actually wanted. It stops
 * a Latin serial being reordered by the Arabic around it, while leaving the
 * block aligned to the reading direction. A run of Latin letters or digits
 * already renders left to right on its own; it never needed to be told.
 *
 * Where an input genuinely must be LTR for the caret and for typing, that is
 * still set explicitly with a dir="ltr" attribute on the field. */
[dir="ltr"], .ltr { direction: ltr; text-align: start; }
.mono {
  font-family: ui-monospace, "Cascadia Mono", Consolas, "Courier New", monospace;
  unicode-bidi: isolate;
  letter-spacing: .02em;
}

/* An INLINE Latin token still forces LTR, and that is the distinction that
   matters: a block follows the reading direction so its value sits under its
   own label, while an inline token forces LTR so a serial in the middle of an
   Arabic sentence is not reordered by it.
 *
 * The concrete case that made this necessary: `(E-9001)` beside an employee
 * name. Brackets are bidi-neutral, so in an Arabic run they take the paragraph
 * direction and mirror, and the reader gets a parenthesised code whose brackets
 * point the wrong way round. Measured, not assumed. */
span.mono { direction: ltr; }

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

/* ---- shell ---------------------------------------------------------------- */

.masthead {
  /* Solid by default so the header is readable everywhere, then translucent
     with a blur only where the browser can actually do it. Without the
     @supports guard, a browser that ignores backdrop-filter would render text
     over whatever artwork happened to be behind it. */
  background: var(--surface);
  border-block-end: 1px solid var(--line);
  position: sticky;
  top: 0;
  z-index: 20;
}

@supports (backdrop-filter: blur(10px)) or (-webkit-backdrop-filter: blur(10px)) {
  .masthead {
    background: rgba(255, 255, 255, .78);
    -webkit-backdrop-filter: blur(14px) saturate(1.4);
    backdrop-filter: blur(14px) saturate(1.4);
    border-block-end-color: rgba(223, 230, 240, .8);
  }
}

.masthead__bar {
  max-width: 1100px;
  margin-inline: auto;
  padding: 12px 18px;
  display: flex;
  align-items: center;
  gap: 14px;
  /* WRAPS. On the handover app an eleven-control non-wrapping header pushed a
     whole screen off the side of the viewport, and the owner reported the page
     as not existing. A link that overflows is indistinguishable from a feature
     that was never built. */
  flex-wrap: wrap;
}

.brand {
  display: flex;
  align-items: center;
  gap: 10px;
  font-weight: 700;
  color: var(--ink);
  text-decoration: none;
  font-size: 1.05rem;
}

/* The real mark, not a coloured square with letters in it. It ships with a
   transparent background so it sits on the header, on the login card, and on
   anything else without carrying a white tile around with it. */
.brand__mark {
  width: 36px;
  height: 36px;
  flex: none;
  display: block;
}
.brand__mark--lg { width: 52px; height: 52px; }

.masthead__spacer { flex: 1 1 auto; }

.nav {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  align-items: center;
}

.nav a {
  display: inline-flex;
  align-items: center;
  min-height: 40px;
  padding-inline: 13px;
  border-radius: 999px;
  color: var(--ink-soft);
  text-decoration: none;
  font-size: .93rem;
  font-weight: 600;
  white-space: nowrap;
}

.nav a:hover { background: var(--line-soft); color: var(--ink); }
.nav a[aria-current="page"] { background: var(--brand-tint); color: var(--brand-dark); }

.who {
  font-size: .86rem;
  color: var(--ink-faint);
  display: flex;
  align-items: center;
  gap: 8px;
}

.main {
  max-width: 1100px;
  margin-inline: auto;
  padding: 26px 18px 72px;
}

.page-head { margin-block-end: 22px; }
.page-head h1 {
  /* NEVER gradient-fill a heading. background-clip:text runs in physical space
     against the reading direction, so a short Arabic word renders as two
     different colours. Found on support365 and reverted. */
  margin: 0 0 4px;
  font-size: 1.6rem;
  line-height: 1.25;
  letter-spacing: -.01em;
}
.page-head p { margin: 0; color: var(--ink-soft); }

/* ---- surfaces ------------------------------------------------------------- */

.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  padding: 20px;
}

.card + .card { margin-block-start: 16px; }
.card__title { margin: 0 0 14px; font-size: 1.05rem; font-weight: 700; }

.grid { display: grid; gap: 16px; }
@media (min-width: 720px) {
  .grid--2 { grid-template-columns: 1fr 1fr; }

  /* auto-fit rather than a fixed four, so a row of tiles distributes evenly
     whatever the count. With exactly four columns, a fifth tile drops onto a
     row of its own and the empty space beside it reads as something that
     failed to load. */
  .grid--4 { grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); }
}

/* Numbers, as tiles rather than a table. A four column table on a 390px phone
   shows two columns and says nothing about the rest, and a clipped column is
   the same as a column that was never rendered. */
.tile {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 18px;
  /* CENTRED, in both languages, and that is a correctness decision as much as
     a visual one. A centred tile has no reading-direction side to be thrown
     to, so the class of bug where an Arabic count landed at the far edge of
     its own card cannot recur here whatever the text direction resolves to.
     It also makes the two languages look identical, which is what was asked
     for. */
  text-align: center;
}
.tile__label {
  font-size: .78rem;
  color: var(--ink-soft);
  font-weight: 600;
  letter-spacing: .02em;
  text-transform: none;
}
.tile__value {
  font-size: 2rem;
  font-weight: 700;
  line-height: 1.15;
  margin-block-start: 6px;
  letter-spacing: -.02em;
}
.tile--accent { background: var(--brand-tint); border-color: #cfe0f8; }
.tile--accent .tile__value { color: var(--brand-dark); }

/* A tile that is a link should say so on hover. Several of them navigate and
   nothing else distinguished them from the ones that do not. */
a.tile { transition: transform .15s ease, box-shadow .15s ease, border-color .15s ease; }
a.tile:hover {
  border-color: #c3d4ea;
  box-shadow: var(--shadow);
  transform: translateY(-2px);
}

/* ---- forms ---------------------------------------------------------------- */

.field { margin-block-end: 16px; }
.field > label {
  display: block;
  font-weight: 600;
  font-size: .92rem;
  margin-block-end: 7px;
  color: var(--ink);
}
.field__hint { font-size: .84rem; color: var(--ink-faint); margin-block-start: 6px; }

/* A FIELD MUST LOOK LIKE A FIELD WHEN IT IS EMPTY.
 *
 * These were white boxes with a hairline border sitting on a white card. Full,
 * they read fine; empty, they were invisible, and a form is mostly empty at the
 * moment somebody has to fill it in. Reported from the real screen: "the field
 * is not appearing, all the thing is white."
 *
 * So an idle field is now TINTED and clearly bordered, and it turns white on
 * focus. The contrast runs the right way round: the box you have not filled in
 * yet is the one that stands out, and the one you are typing in is the
 * brightest thing on the card. */
.input {
  width: 100%;
  min-height: var(--touch);
  padding: 11px 14px;
  border: 1.5px solid var(--field-line);
  border-radius: var(--radius-sm);
  background: var(--field);
  color: var(--ink);
  font: inherit;
  box-shadow: inset 0 1px 2px rgba(22, 32, 46, .04);
}

.input:hover { border-color: #a9bcd6; }

.input:focus,
.input:focus-visible {
  outline: 3px solid rgba(18, 99, 196, .22);
  outline-offset: 1px;
  border-color: var(--brand);
  background: #fff;
  box-shadow: inset 0 1px 2px rgba(22, 32, 46, .03);
}

.input::placeholder { color: #9aa7bb; }

/* A select needs its own arrow, or on some platforms it renders as a plain box
   and stops looking like something you can open. */
select.input {
  appearance: none;
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='none' stroke='%2355637a' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 8l5 5 5-5'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: left 12px center;
  background-size: 18px;
  padding-inline-end: 14px;
  padding-inline-start: 40px;
}
[dir="ltr"] select.input,
html[dir="ltr"] select.input { background-position: right 12px center; }

textarea.input { min-height: 96px; resize: vertical; }

/* A code is read off a phone and typed on another screen, so it gets room. */
.input--code {
  font-family: ui-monospace, Consolas, monospace;
  font-size: 1.7rem;
  letter-spacing: .5em;
  text-align: center;
  direction: ltr;
  padding-inline-start: .5em;
}

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: var(--touch);
  padding-inline: 22px;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  background: linear-gradient(180deg, #1a6fd0, var(--brand));
  color: #fff;
  font: inherit;
  font-weight: 600;
  cursor: pointer;
  text-decoration: none;
  box-shadow: 0 1px 2px rgba(13, 75, 150, .28), 0 2px 8px rgba(13, 75, 150, .16);
}
.btn:hover { background: linear-gradient(180deg, var(--brand), var(--brand-dark)); }

/* A pressed control should move. On a phone in a corridor the tap feedback is
   often the only confirmation the person gets before the next screen loads. */
.btn:active { transform: translateY(1px); box-shadow: 0 1px 2px rgba(13, 75, 150, .3); }

.btn:focus-visible { outline: 3px solid rgba(18, 99, 196, .38); outline-offset: 2px; }
.btn[disabled] { opacity: .5; cursor: not-allowed; box-shadow: none; transform: none; }
.btn--block { width: 100%; }

.btn--quiet {
  background: var(--surface);
  color: var(--brand-dark);
  border-color: var(--line);
  box-shadow: var(--shadow-sm);
}
.btn--quiet:hover { background: var(--line-soft); border-color: #c3d4ea; }
.btn--quiet:active { transform: translateY(1px); }

.btn-row { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; }

/* ---- messages ------------------------------------------------------------- */

.note {
  border-radius: var(--radius-sm);
  padding: 12px 15px;
  margin-block-end: 16px;
  font-size: .94rem;
  border: 1px solid transparent;
}
.note--ok     { background: var(--ok-tint);     border-color: #bfe4d0; color: #0e5c37; }
.note--warn   { background: var(--warn-tint);   border-color: #f2d5a8; color: #7d4400; }
.note--error  { background: var(--danger-tint); border-color: #f3c3c0; color: #8c1c16; }
.note--info   { background: var(--brand-tint);  border-color: #cfe0f8; color: var(--brand-dark); }

/* ---- auth screen ---------------------------------------------------------- */

/* TWO COMPOSITIONS, NOT TWO SIZES, and mobile gets its own.
 *
 * background-size: cover on a 375px phone crops a 16:9 image to roughly a
 * quarter of the frame, so a landscape backdrop becomes a meaningless detail
 * of itself. A wider or smaller file does not fix that, because a landscape
 * picture cropped to 9:16 is a different picture. The tall composition is the
 * DEFAULT and the wide one is the override, so the narrowest screen is the one
 * that gets art made for it rather than the one that gets leftovers.
 *
 * The navy-free base colour paints first and the card is opaque, so the art can
 * be replaced later without anything becoming unreadable. */
.auth {
  min-height: 100vh;
  display: grid;
  place-items: center;
  padding: 24px 18px;
  background-color: var(--bg);
  background-image: url("/assets/img/bg-tall.jpg");
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}

@media (min-width: 768px) {
  .auth { background-image: url("/assets/img/bg-wide.jpg"); }
}

/* Save-Data or a slow connection keeps the plain background. Somebody signing
   in from a stockroom on a bad phone signal should not wait on decoration. */
@media (prefers-reduced-data: reduce) {
  .auth { background-image: none; }
}
.auth__card {
  width: 100%;
  max-width: 430px;
  background: var(--surface);
  border: 1px solid rgba(255, 255, 255, .7);
  border-radius: 22px;
  /* Deeper than a normal card, because this one floats over artwork rather
     than sitting on the page background. */
  box-shadow: 0 2px 6px rgba(22, 32, 46, .06), 0 18px 50px rgba(22, 32, 46, .14);
  padding: 32px 28px;
}
.auth__brand { display: flex; align-items: center; gap: 13px; margin-block-end: 22px; }
.auth__brand strong { font-size: 1.05rem; }
.auth__card h1 { margin: 0 0 6px; font-size: 1.4rem; letter-spacing: -.01em; }
.auth__card .lead { margin: 0 0 22px; color: var(--ink-soft); font-size: .95rem; }

/* ---- lists ---------------------------------------------------------------- */

.rows { display: grid; gap: 10px; }
.row {
  display: flex;
  gap: 14px;
  align-items: center;
  padding: 13px 15px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  text-decoration: none;
  color: inherit;
}
.row:hover { border-color: #c3d4ea; box-shadow: var(--shadow-sm); }
.row__main { flex: 1 1 auto; min-width: 0; }
.row__title { font-weight: 600; }
.row__meta { font-size: .85rem; color: var(--ink-soft); }
.row__meta > * { white-space: nowrap; }

.badge {
  display: inline-flex;
  align-items: center;
  padding: 3px 10px;
  border-radius: 999px;
  font-size: .78rem;
  font-weight: 700;
  background: var(--line-soft);
  color: var(--ink-soft);
  white-space: nowrap;
}
.badge--ok    { background: var(--ok-tint);    color: #0e5c37; }
.badge--brand { background: var(--brand-tint); color: var(--brand-dark); }
.badge--warn  { background: var(--warn-tint);  color: #7d4400; }

/* ---- progress ring ---------------------------------------------------------
 * How far through the count are we, as one shape.
 *
 * A conic-gradient, so it is a single element with no library, no JavaScript
 * and no SVG to keep in step with the numbers. The percentage is passed in as
 * a custom property, and the figure is repeated as text in the middle, because
 * a ring alone is a picture of a number rather than the number.
 */

.ring-card {
  display: flex;
  align-items: center;
  gap: 22px;
  flex-wrap: wrap;
}

.ring {
  --pct: 0;
  --size: 132px;
  width: var(--size);
  height: var(--size);
  flex: none;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background:
    conic-gradient(var(--brand) calc(var(--pct) * 1%), var(--line-soft) 0);
  position: relative;
}

/* The hole. An inset white disc rather than a mask, which every browser here
   supports without qualification. */
.ring::before {
  content: "";
  position: absolute;
  inset: 13px;
  border-radius: 50%;
  background: var(--surface);
}

.ring__inner { position: relative; text-align: center; line-height: 1.15; }
.ring__pct { font-size: 1.75rem; font-weight: 700; letter-spacing: -.02em; }
.ring__label { font-size: .74rem; color: var(--ink-soft); font-weight: 600; }

.ring-facts { display: grid; gap: 7px; min-width: 0; flex: 1 1 220px; }
.ring-fact { display: flex; align-items: baseline; gap: 9px; font-size: .93rem; }
.ring-fact__dot { width: 11px; height: 11px; border-radius: 3px; flex: none; }
.ring-fact__n { font-weight: 700; }

/* An empty report is still a report. It says what to do next instead of
   showing a blank card, which reads as something failing to load. */
.empty__art {
  width: 190px;
  height: 190px;
  max-width: 60%;
  margin-inline: auto;
  margin-block-end: 14px;
  display: block;
}

/* ---- charts ----------------------------------------------------------------
 * Bars are divs with a percentage width. No charting library is loaded, and
 * none is needed: this works with JavaScript off, prints, and mirrors in
 * Arabic without a single direction override, because a flex row in a logical
 * layout already runs the right way.
 */

.chart { display: grid; gap: 12px; }

.chart__row {
  display: grid;
  grid-template-columns: minmax(120px, 1.1fr) minmax(90px, 3fr) auto;
  gap: 14px;
  align-items: center;
}

.chart__label {
  font-size: .92rem;
  font-weight: 600;
  display: flex;
  align-items: center;
  gap: 7px;
  min-width: 0;
}
.chart__sub { font-weight: 400; color: var(--ink-faint); font-size: .82rem; }

.chart__track { display: flex; gap: 3px; align-items: center; width: 100%; min-width: 0; }

/* The width lives here, as a percentage of the track. Two bars in one track
   (counted and outstanding) are both percentages of the same maximum, so they
   sum to at most 100% and always fit. */
.bar { display: block; flex: 0 0 auto; min-width: 3px; }
.bar__fill {
  display: block;
  width: 100%;
  height: 22px;
  border-radius: 5px;
}
.bar__fill--brand { background: linear-gradient(90deg, #2a7fd8, var(--brand)); }
.bar__fill--ok    { background: linear-gradient(90deg, #2a9d6a, var(--ok)); }

/* Amber only ever means attention, here as everywhere else: on these charts it
   is exclusively "expected and not yet counted". It is never used to colour a
   normal quantity. */
.bar__fill--warn  { background: linear-gradient(90deg, #d98b2b, var(--warn)); }

.chart__value { font-weight: 700; white-space: nowrap; text-align: end; }
.chart__of { display: block; font-size: .76rem; font-weight: 500; color: var(--ink-faint); }

.legend {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 18px;
  align-items: center;
  margin-block-end: 0;
  font-size: .84rem;
  color: var(--ink-soft);
}
.legend__key {
  width: 13px; height: 13px;
  border-radius: 4px;
  display: inline-block;
  margin-inline-end: 6px;
  vertical-align: -2px;
}
.legend__key--ok   { background: var(--ok); }
.legend__key--warn { background: var(--warn); }

.tile--warn { background: var(--warn-tint); border-color: #f2d5a8; }
.tile--warn .tile__value { color: #7d4400; }

.btn--danger {
  background: linear-gradient(180deg, #c8362e, var(--danger));
  box-shadow: 0 1px 2px rgba(179, 38, 30, .3), 0 2px 8px rgba(179, 38, 30, .18);
}
.btn--danger:hover { background: linear-gradient(180deg, var(--danger), #8c1c16); }

/* On a phone the label and the bar stack, because three columns in 375px gives
   a 40px bar and a truncated name, and a chart nobody can read is decoration. */
@media (max-width: 600px) {
  .chart__row { grid-template-columns: 1fr auto; }
  .chart__track { grid-column: 1 / -1; }
}

.empty {
  text-align: center;
  padding: 40px 20px;
  color: var(--ink-soft);
  border: 1px dashed var(--line);
  border-radius: var(--radius);
  background: var(--surface);
}

/* Wide content scrolls inside its own box AND says so with a visible edge.
   Silent clipping is how a column disappears without anybody noticing. */
.scroll-x {
  overflow-x: auto;
  border-inline: 1px solid var(--line-soft);
}

.footer {
  max-width: 1100px;
  margin-inline: auto;
  padding: 0 18px 34px;
  color: var(--ink-faint);
  font-size: .82rem;
}

@media (prefers-reduced-motion: no-preference) {
  .btn, .row, .nav a { transition: background-color .15s ease, border-color .15s ease, box-shadow .15s ease, transform .12s ease; }
}

/* Someone who has asked their device for less motion gets none of it, and that
   includes the lift on tiles and the press on buttons. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition: none !important; animation: none !important; }
  .btn:active, a.tile:hover { transform: none; }
}

/* ---- print -----------------------------------------------------------------
 * A report gets printed and handed to somebody, which is most of the point of
 * having one. Without this the navigation, the export buttons and the page
 * artwork all come out on paper and the charts lose their fills, because
 * browsers drop background colours by default.
 */
@media print {
  body {
    background: #fff !important;
    color: #000;
    font-size: 11pt;
  }

  .masthead, .nav, .btn, .btn-row, .footer, form { display: none !important; }

  .main { max-width: none; padding: 0; }

  .card, .tile {
    box-shadow: none;
    border: 1px solid #bbb;
    break-inside: avoid;
    page-break-inside: avoid;
  }

  /* Bars and rings are backgrounds, and a chart printed without its fill is a
     row of empty boxes. */
  .bar__fill, .ring, .ring-fact__dot, .badge, .tile--accent, .tile--warn {
    -webkit-print-color-adjust: exact;
    print-color-adjust: exact;
  }

  .grid--4 { grid-template-columns: repeat(4, 1fr); }
  .grid--2 { grid-template-columns: 1fr 1fr; }

  a[href]::after { content: ""; }   /* no URLs printed after every link */
}
