/* ==========================================================================
   DLG Academy stylesheet
   Desert Legal Group onboarding and policy acknowledgment platform.
   Internal draft, September 5, 2026. Pending attorney and owner review.

   WHERE THIS FILE COMES FROM
   Two sources and no third.

   1. The TOKEN BLOCK immediately below is design/tokens.css, carried over
      verbatim, comments and all. Its own header names where every hex in it
      came from: the firm's brand file at
      /srv/dlg/claude/skills/dlg-writing-scheme/references/brand.md for the
      brand core, the divorce course page at
      https://desertlegalgroup.com/divorce-course/ for the extended greens and
      the component geometry, and /docker/marketing/app/static/app.css together
      with /docker/financials/app/static/app.css for the status set.

   2. The COMPONENT LAYER after it implements design/STYLE.md section by
      section, in STYLE.md's own order. Every rule names a token.

   THE ONE RULE THIS FILE ENFORCES ON ITSELF
   No hex literal, and no invented color of any kind, appears below the line
   marked END OF TOKEN BLOCK. A rule that seems to need a value which is not a
   token is a request for a new token in design/tokens.css with a reason next
   to it, not a literal here. Grep for a hash character after that line and the
   answer should be nothing.

   A NOTE ON THE WEBFONT
   STYLE.md asks for Playfair Display 700 self-hosted as woff2 under
   app/static/fonts. The @font-face rule that loads it is in the component
   layer below. The woff2 itself is not in the repository yet: Playfair Display
   is installed on this server only as a variable TTF at
   /usr/local/share/fonts/playfair-display, and neither fonttools nor brotli is
   present to convert it. Until somebody adds the file, --display falls through
   its own stack to Georgia and then to Times New Roman, both of which are
   serif and both of which read on brand. Nothing on any screen depends on the
   webfont arriving.
   ========================================================================== */

:root{
  /* ---- Brand core. Source: dlg-writing-scheme/references/brand.md ---- */
  --forest:        #1C453D;  /* Deep Forest Green, primary */
  --orange:        #E06B44;  /* Burnt Orange, accent */
  --silver:        #C9D0CD;  /* Chrome Silver, neutral */
  --cream:         #F4F2EC;  /* Cream, warm ground */
  --ink:           #1A1A1A;  /* Ink, body text on light */
  --white:         #FFFFFF;

  /* ---- Extended greens. Source: the divorce course page ---- */
  --forest-deep:   #142827;  /* Divi theme ink and top header fill */
  --forest-mid:    #27584E;  /* the page's section fill */
  --forest-soft:   #376F64;  /* the page's form submit fill */

  /* ---- Surfaces ---- */
  --surface:       var(--white);
  --surface-alt:   var(--cream);
  --surface-dark:  var(--forest);
  --surface-deep:  var(--forest-deep);

  /* ---- Text ---- */
  --text-strong:   var(--ink);          /* headings and emphasis on light */
  --text-body:     var(--forest);       /* long body copy on light */
  --text-muted:    var(--forest-soft);  /* labels, meta, timestamps */
  --text-on-dark:  var(--cream);
  --text-on-dark-muted: var(--silver);

  /* ---- Lines ---- */
  --border:        var(--silver);       /* decorative dividers only */
  --border-strong: var(--forest-soft);  /* inputs, focus rings, real edges */
  --border-card:   var(--forest);       /* the 2px card border from the page */

  /* ---- Status. Source: /docker/{marketing,financials}/app/static/app.css ---- */
  --good:          #3FA783;
  --warn:          #E8C34A;
  --bad:           #E06B44;
  --info:          #4285C0;
  /* Status colors are chip FILLS with --ink text, never colored text on white.
     See the contrast table.

     CHANGED, role only, hex untouched: --info is not a chip fill in this app.
     Ink on #4285C0 measures 4.43:1, which is short of the 4.5:1 AA bar for
     normal text, and white on it measures 3.93:1, which is worse. Both were
     computed with the WCAG 2.1 formula, and neither pair appears in the design
     reference contrast table, so this is a gap that surfaced here rather than a
     disagreement with the proposal. --info is kept for non-text work only: the
     4px left rule on an information banner, an icon, a chart series. The
     assigned chip takes --silver instead, where ink measures 11.10:1.

     --bad and --orange are the same hex. That is how both /docker dashboards
     ship it and it is not changed here. It means an overdue chip and a primary
     button carry the same fill, so the two are told apart by shape and by
     border instead: the button is a 4px radius rectangle with no border, the
     chip is a pill with a 2px --forest border and the word "Overdue" in it.
     Worth the owner's eye at design review. */

  /* ---- Type. Source: brand.md, and the page's own #main-content override ---- */
  --display: "Playfair Display", Georgia, "Times New Roman", serif;
  --body:    "Times New Roman", Times, Georgia, serif;

  /* Type scale, derived from the page and reduced for a reading app.
     Page desktop sizes in comments. */
  --fs-h1:    2.375rem;  /* 38px. Page section H1 is 46px, its own Course Outline override is 38px */
  --fs-h2:    1.75rem;   /* 28px. Page sub-CTA H2 is 41px */
  --fs-h3:    1.3125rem; /* 21px */
  --fs-h4:    1.1875rem; /* 19px. Matches the page's card title exactly */
  --fs-body:  1.0625rem; /* 17px. Matches the page's body copy exactly */
  --fs-small: 0.875rem;  /* 14px. Matches the page's card body exactly */
  --fs-micro: 0.8125rem; /* 13px. Labels and timestamps */

  --lh-display: 1.12;  /* the page's heading line height */
  --lh-body:    1.55;  /* brand.md says about 1.5; 1.55 reads better at 17px */
  --lh-tight:   1.2;

  --ls-eyebrow: 0.09em; /* brand.md gives 1px on an eyebrow at label size */
  --ls-card-title: 0.075em; /* the page's 1.4px at 19px */

  /* ---- Spacing. A fixed 4px scale replacing the page's percentage padding ---- */
  --sp-1: 0.25rem;  /* 4  */
  --sp-2: 0.5rem;   /* 8  */
  --sp-3: 0.75rem;  /* 12, the page's card grid column gap */
  --sp-4: 1rem;     /* 16, the page's card row gap */
  --sp-5: 1.25rem;  /* 20, the page's card padding */
  --sp-6: 1.5rem;   /* 24 */
  --sp-8: 2rem;     /* 32 */
  --sp-10: 2.5rem;  /* 40 */
  --sp-12: 3rem;    /* 48, the page's Course Outline section padding */
  --sp-16: 4rem;    /* 64 */
  --sp-section: var(--sp-12);
  --sp-section-lg: var(--sp-16);

  /* ---- Radius. Source: the page's rendered values ---- */
  --r-sm:  4px;   /* every button on the page */
  --r-md:  14px;  /* every module card on the page */
  --r-lg:  20px;  /* the page's image columns */
  --r-pill: 999px;
  --r-round: 50%; /* the page's numeral badge */

  /* ---- Shadow. Source: the page's rendered values ---- */
  --shadow-card:  0 8px 18px rgba(20,40,35,0.08);
  --shadow-hover: 0 16px 34px rgba(28,69,61,0.32); /* page value re-tinted to --forest */
  --shadow-modal: 0 18px 40px rgba(18,48,41,0.10); /* from the site's own .dlgbrief block */

  /* ---- Layout ---- */
  --maxw:      1120px; /* matches /srv/dlg/dlg-pi-project/assets/base.css --maxw */
  --maxw-read: 68ch;   /* policy and SOP prose */
  --gutter:    var(--sp-5);

  /* ---- Motion. Source: the page's card transition ---- */
  --t-fast: .12s ease;
  --t-base: .22s ease;

  /* ======================================================================
     ADDED for the app. Everything below this line is new against the design
     reference proposal. No new hex is introduced: every value resolves to a
     token already defined above.
     ====================================================================== */

  /* ---- Focus ----
     CHANGED from the proposal. The proposal set the focus outline to
     3px solid var(--orange). Two measured problems with that. Orange on the
     cream surface is 2.95:1, under the 3:1 bar a focus indicator has to clear
     as a non-text UI component. And the primary button is itself an orange
     fill, so an orange ring on the primary action is invisible, which is the
     one control a keyboard user most needs to find. Forest measures 10.67:1 on
     white, 9.53:1 on cream, 6.80:1 on the silver chip, 6.27:1 on the warn
     chip, 3.59:1 on the good chip and 3.23:1 on the orange button. Every one of
     those clears 3:1, so forest is the ring. */
  --focus-ring:         var(--forest);
  /* ADDED. Forest disappears on the forest header, the forest nav and the
     signed chip. Cream on forest is 9.53:1. Any element sitting on a dark
     surface takes this ring instead. */
  --focus-ring-inverse: var(--cream);
  --focus-width:        3px;
  --focus-offset:       2px;

  /* ---- Chip fills. ADDED. Roles only, no new hex ----
     Every chip is a colored fill with --ink text and a word inside it, so the
     meaning never depends on color alone. Measured ink-on-fill ratios in the
     comment. The signed chip is the one exception: forest fill, cream text. */
  --chip-assigned:      var(--silver);      /* ink 11.10:1 */
  --chip-due-soon:      var(--warn);        /* ink 10.22:1 */
  --chip-overdue:       var(--bad);         /* ink  5.27:1 */
  --chip-complete:      var(--good);        /* ink  5.86:1 */
  --chip-signed:        var(--forest);      /* cream 9.53:1 */
  --chip-text:          var(--ink);
  --chip-text-inverse:  var(--cream);
  --chip-edge-overdue:  var(--forest);      /* 2px, tells the chip from the button */

  /* ---- Review status. ADDED. Decision 14: draft, needs Cory, approved ----
     Reuses the chip fills rather than adding a second color language. */
  --review-draft:       var(--silver);
  --review-needs:       var(--warn);
  --review-approved:    var(--good);

  /* ---- Touch targets. ADDED. Staff read and sign on phones ---- */
  --tap:        44px;   /* nothing tappable is smaller than this */
  --tap-input:  16px;   /* iOS Safari zooms a focused input under 16px */

  /* ---- Reader. ADDED. The document reader is the app's longest surface ---- */
  --reader-maxw:   var(--maxw-read);
  --reader-pdf-h:  75vh;   /* iframe height for the browser PDF viewer, desktop */
  --reader-lh:     1.6;    /* a notch above --lh-body for uninterrupted policy prose */

  /* ---- Progress. ADDED ---- */
  --progress-track: var(--silver);
  --progress-fill:  var(--forest);
  --progress-h:     10px;

  /* ---- Breakpoints. ADDED, documentation only ----
     CSS media queries cannot read a custom property, so these four cannot be
     used in the @media rules below and the pixel values there are typed out.
     They are recorded here so the set has one home and a reviewer can see it.
     The values are Divi's, which is what the firm's website already uses, so
     the app and the site break at the same widths.
       --bp-xs  479px  small phone
       --bp-sm  768px  phone to tablet boundary (Divi phone breakpoint is 767px)
       --bp-md  981px  tablet to desktop boundary (Divi tablet breakpoint is 980px)
       --bp-lg 1200px  wide desktop */
  --bp-xs:  479px;
  --bp-sm:  768px;
  --bp-md:  981px;
  --bp-lg: 1200px;

  /* ---- Layout, app shell. ADDED ---- */
  --nav-w:        248px;  /* left rail width at --bp-md and above */
  --header-h:     64px;   /* fixed top bar, all widths */
  --tabbar-h:     56px;   /* phone bottom bar, staff views only */
}

/* ==========================================================================
   Mobile type scale and rhythm. Carried from the design reference,
   "Responsive rule set". Base is mobile. Everything above is a progressive
   enhancement.
   ========================================================================== */
:root{
  --fs-h1: 1.9375rem;  /* 31px, the page's own mobile H1 */
  --fs-h2: 1.625rem;   /* 26px, the page's own mobile H2 */
  --fs-h3: 1.1875rem;  /* 19px */
  --fs-body: 1.0625rem;/* 17px, unchanged from desktop, deliberately */
  --sp-section: 2rem;  /* 32px */
  --gutter: 1rem;

  /* ADDED to the proposal's mobile block, which stopped at h3. The app has
     card titles, table labels, chips and timestamps on every phone screen and
     each of them needs a size at this width. */
  --fs-h4: 1.125rem;   /* 18px. One notch under the 19px desktop card title, so
                          an uppercase letter-spaced card title still fits a
                          390px column on two lines rather than three. */
  --fs-small: 0.9375rem; /* 15px. The 14px desktop card body is the page's own
                          value and it holds on a wide card. On a 390px phone
                          the same text is the assignment summary a member of
                          staff reads to decide what to open, so it steps up. */
  /* CHANGED from the desktop 13px. A 13px Times New Roman timestamp or chip
     label on a phone is genuinely hard work, and in this app the micro size
     carries due dates and status words that decide what somebody does next.
     Desktop keeps 13px, restored in the 981px query below. */
  --fs-micro: 0.875rem; /* 14px */

  --reader-pdf-h: 65vh; /* a phone has less height to give the viewer */
}

@media (min-width:768px){
  :root{ --fs-h1:2.125rem; --fs-h2:1.6875rem; --sp-section:2.5rem; --gutter:1.25rem; }
}
@media (min-width:981px){
  :root{ --fs-h1:2.375rem; --fs-h2:1.75rem; --fs-h3:1.3125rem;
         --sp-section:3rem; --gutter:1.5rem; }
  /* ADDED: the rest of the scale returns to its desktop value here. */
  :root{ --fs-h4:1.1875rem; --fs-small:0.875rem; --fs-micro:0.8125rem;
         --reader-pdf-h:75vh; }
}

/* ==========================================================================
   END OF TOKEN BLOCK
   Everything below is the component layer from design/STYLE.md. No hex.
   ========================================================================== */

/* --------------------------------------------------------------------------
   0. Reset, font loading, and the two things every page needs
   -------------------------------------------------------------------------- */

/* STYLE.md, Font loading: self-hosted, font-display swap, no Google Fonts
   request. The fleet has no build step, so one rule is the whole mechanism.
   Playfair Display is display type only and never runs below --fs-h3. */
@font-face{
  font-family:"Playfair Display";
  src:url("/static/fonts/playfair-display-700.woff2") format("woff2");
  font-weight:700;
  font-style:normal;
  font-display:swap;
}

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

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

body{
  margin:0;
  padding-top:var(--header-h);
  background:var(--surface);
  color:var(--text-body);
  font-family:var(--body);
  font-size:var(--fs-body);
  line-height:var(--lh-body);
}

img{ max-width:100%; height:auto; border:0; }

/* A fieldset is a grouping, not a box. Left at the browser default it draws a
   frame the design does not have and, worse, it floats the legend across the
   top border, which turns the quiz question into text sitting on a line. The
   group is named by its legend and separated by the spacing scale, the way
   every other group in the app is. */
fieldset{ border:0; padding:0; margin:0; min-width:0; }
legend{ display:block; padding:0; width:100%; }

h1,h2,h3,h4{ margin:0; font-family:var(--display); font-weight:700; color:var(--text-strong); }
h1{ font-size:var(--fs-h1); line-height:var(--lh-display); }
h2{ font-size:var(--fs-h2); line-height:var(--lh-display); }
h3{ font-size:var(--fs-h3); line-height:var(--lh-tight); }
/* h4 is the card title role: --body, uppercase, letter spaced. STYLE.md keeps
   Playfair out of label sizes because it turns to mush there. */
h4{ font-family:var(--body); font-size:var(--fs-h4); line-height:var(--lh-tight);
    text-transform:uppercase; letter-spacing:var(--ls-card-title); }

p{ margin:0 0 var(--sp-4); }
p:last-child{ margin-bottom:0; }

a{ color:var(--text-body); }
a:hover{ color:var(--text-strong); }

/* Visible to a screen reader, invisible on the page. Used for the hidden
   table header row on a phone, for legends, and for live regions. */
.sr-only{
  position:absolute; width:1px; height:1px; padding:0; margin:-1px;
  overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0;
}

/* The eyebrow role from the type table. */
.eyebrow{
  font-family:var(--body); font-weight:700; font-size:var(--fs-micro);
  line-height:1.2; text-transform:uppercase; letter-spacing:var(--ls-eyebrow);
  color:var(--text-muted); margin:0 0 var(--sp-2);
}

/* --------------------------------------------------------------------------
   1. Focus, the same everywhere
   STYLE.md section 18: every interactive element has a visible indicator, and
   outline:none never appears without a replacement in the same rule.
   -------------------------------------------------------------------------- */

:focus-visible{
  outline:var(--focus-width) solid var(--focus-ring);
  outline-offset:var(--focus-offset);
}
/* Forest disappears on a forest surface. Anything inside a dark region takes
   the cream ring instead. */
.app-header :focus-visible,
.nav :focus-visible,
.nav-panel :focus-visible,
.tabbar :focus-visible,
.toast :focus-visible,
.card--dark :focus-visible,
.signin :focus-visible,
.on-dark :focus-visible{
  outline-color:var(--focus-ring-inverse);
}

.skip-link{
  position:absolute; left:var(--sp-3); top:var(--sp-3);
  transform:translateY(-200%);
  z-index:60;
  background:var(--surface); color:var(--text-body);
  border:2px solid var(--border-card); border-radius:var(--r-sm);
  padding:var(--sp-3) var(--sp-4);
  font-size:var(--fs-small); text-decoration:none;
  transition:transform var(--t-fast);
}
.skip-link:focus{ transform:translateY(0); }

/* --------------------------------------------------------------------------
   2. Page shell: header, navigation by breakpoint, main, footer
   -------------------------------------------------------------------------- */

.app-header{
  position:fixed; inset:0 0 auto 0; z-index:50;
  height:var(--header-h);
  background:var(--surface-dark);
  color:var(--text-on-dark);
  display:flex; align-items:center; gap:var(--sp-4);
  padding:0 var(--gutter);
}

/* The mark, left, linking to the role's home screen. */
.brand{
  display:inline-flex; align-items:center; gap:var(--sp-3);
  text-decoration:none; color:var(--text-on-dark);
  min-height:var(--tap); padding-right:var(--sp-2);
}
.brand__img{ height:32px; width:auto; display:block; }

/* The typographic wordmark. It stands in for the mark asset on a forest
   ground, where brand.md permits neither the full colour file nor a knockout
   made here. app/static/brand/README.md carries the whole reason and the ask.
   The shape follows the mark: DLG large, a burnt orange rule, then the firm
   name small and letter spaced. */
.wordmark{ display:block; line-height:1; }
.wordmark__dlg{
  display:block; font-family:var(--display); font-weight:700;
  font-size:var(--fs-h3); letter-spacing:.06em; color:var(--text-on-dark);
}
.wordmark__rule{
  display:block; height:2px; width:100%; margin:var(--sp-1) 0;
  background:var(--orange);
}
.wordmark__name{
  display:block; font-family:var(--body); font-size:var(--fs-micro);
  text-transform:uppercase; letter-spacing:var(--ls-eyebrow);
  color:var(--text-on-dark-muted);
  /* The firm's name is a mark and a mark does not wrap. It sets to about
     165px at the phone label size, which the 64px header has room for beside
     the user menu at 320px. */
  white-space:nowrap;
}

.header__spacer{ flex:1 1 auto; }

/* The user menu. A button, a chevron, and a panel. No navigation lives here on
   desktop, because the rail carries it. */
.usermenu{ position:relative; }
.usermenu__btn{
  display:inline-flex; align-items:center; gap:var(--sp-2);
  min-height:var(--tap); padding:var(--sp-2) var(--sp-3);
  background:none; border:0; border-radius:var(--r-sm);
  font-family:var(--body); font-size:var(--fs-small);
  color:var(--text-on-dark); cursor:pointer;
}
.usermenu__btn:hover{ background:var(--surface-deep); }
.usermenu__chev{
  display:inline-block; width:8px; height:8px;
  border-right:2px solid currentColor; border-bottom:2px solid currentColor;
  transform:translateY(-2px) rotate(45deg);
}
.usermenu__panel{
  position:absolute; right:0; top:calc(100% + var(--sp-2));
  min-width:230px; padding:var(--sp-2);
  background:var(--surface); color:var(--text-body);
  border:2px solid var(--border-card); border-radius:var(--r-md);
  box-shadow:var(--shadow-modal);
  list-style:none; margin:0;
}
.usermenu__panel[hidden]{ display:none; }
.usermenu__panel a{
  display:block; min-height:var(--tap); line-height:var(--tap);
  padding:0 var(--sp-3); border-radius:var(--r-sm);
  font-size:var(--fs-small); text-decoration:none; color:var(--text-body);
}
.usermenu__panel a:hover{ background:var(--surface-alt); color:var(--text-strong); }
/* Sign out is a form, because it changes state and goes through the same token
   check every other state-changing request does. It has to read as the item
   above it rather than as a button dropped into a menu. */
.usermenu__signout{ margin:0; }
.usermenu__signout button{
  display:block; width:100%; text-align:left;
  min-height:var(--tap); line-height:var(--tap);
  padding:0 var(--sp-3); border:0; border-radius:var(--r-sm);
  background:none; color:var(--text-body);
  font-family:inherit; font-size:var(--fs-small); cursor:pointer;
}
.usermenu__signout button:hover{ background:var(--surface-alt); color:var(--text-strong); }

/* The body grid. One column on a phone and a tablet, rail plus content at
   --bp-md. The rail is a grid column rather than a fixed element, so it runs
   full height and scrolls with the page. */
.app-body{ display:grid; grid-template-columns:1fr; min-height:calc(100vh - var(--header-h)); }

/* Navigation, one list of destinations in one order at every width.
   Below 768px this element is the horizontal bar's phone form and is hidden,
   because a phone takes the tab bar or the disclosure panel instead. */
.nav{ background:var(--surface-dark); color:var(--text-on-dark); display:none; }
.nav__list{ list-style:none; margin:0; padding:var(--sp-3) 0; }
.nav__section{
  padding:var(--sp-4) var(--sp-5) var(--sp-2);
  font-family:var(--body); font-weight:700; font-size:var(--fs-micro);
  text-transform:uppercase; letter-spacing:var(--ls-eyebrow);
  color:var(--text-on-dark-muted);
}
.nav__link{
  display:flex; align-items:center; gap:var(--sp-3);
  padding:var(--sp-3) var(--sp-5);
  font-size:var(--fs-body); color:var(--text-on-dark);
  text-decoration:none;
  border-left:3px solid transparent;
}
.nav__link:hover{ background:var(--surface-deep); color:var(--white); }
.nav__link.is-current{
  border-left-color:var(--orange);
  color:var(--white);
  background:var(--surface-deep);
}
.nav__count{
  margin-left:auto; font-size:var(--fs-micro); color:var(--text-on-dark-muted);
}

/* The phone bottom bar, staff views only, at most four destinations. */
.tabbar{
  position:fixed; inset:auto 0 0 0; z-index:45;
  height:var(--tabbar-h);
  background:var(--surface-dark); color:var(--text-on-dark);
  display:flex;
}
.tabbar__link{
  flex:1 1 0; display:flex; flex-direction:column;
  align-items:center; justify-content:center; gap:var(--sp-1);
  min-height:var(--tap);
  font-size:var(--fs-micro); color:var(--text-on-dark);
  text-decoration:none;
  border-top:3px solid transparent;
}
.tabbar__link.is-current{ border-top-color:var(--orange); color:var(--white); }
body.has-tabbar{ padding-bottom:var(--tabbar-h); }

/* The admin phone disclosure. A button in the header, a full height panel over
   the page with the same items as the rail, focus trapped, Escape closes. */
.nav-toggle{
  display:inline-flex; align-items:center; justify-content:center;
  width:var(--tap); height:var(--tap);
  background:none; border:0; border-radius:var(--r-sm);
  color:var(--text-on-dark); cursor:pointer;
}
.nav-toggle__bars,
.nav-toggle__bars::before,
.nav-toggle__bars::after{
  display:block; width:22px; height:2px; background:currentColor; content:"";
}
.nav-toggle__bars::before{ transform:translateY(-7px); }
.nav-toggle__bars::after{ transform:translateY(5px); }
.nav-panel{
  position:fixed; inset:var(--header-h) 0 0 auto; z-index:55;
  width:min(320px,86vw);
  background:var(--surface-dark); color:var(--text-on-dark);
  overflow-y:auto;
}
.nav-panel[hidden]{ display:none; }
.nav-panel__head{
  display:flex; align-items:center; justify-content:space-between;
  padding:var(--sp-3) var(--sp-5);
}
.nav-panel__close{
  min-width:var(--tap); min-height:var(--tap);
  background:none; border:0; color:var(--text-on-dark);
  font-family:var(--body); font-size:var(--fs-body); cursor:pointer;
}
.nav-scrim{
  position:fixed; inset:var(--header-h) 0 0 0; z-index:54;
  background:var(--surface-deep);
  background:color-mix(in srgb, var(--forest-deep) 62%, transparent);
}
.nav-scrim[hidden]{ display:none; }

/* Main region and footer. */
/* min-width:0 is load bearing. A grid item's default minimum is its
   min-content width, so without this one long unbreakable thing inside the
   main region widens the whole column and the page gains a horizontal
   scrollbar at 320px. The rule says the column may be narrower than its
   contents, and anything that genuinely cannot shrink gets its own scroller. */
.main{ padding:var(--sp-6) var(--gutter) var(--sp-10); min-width:0; }
.page{ max-width:var(--maxw); margin:0 auto; }

.app-footer{
  padding:var(--sp-8) var(--gutter) var(--sp-10);
  background:var(--surface);
}
.app-footer p{
  max-width:var(--maxw); margin:0 auto;
  font-size:var(--fs-micro); line-height:1.35; color:var(--text-muted);
}

/* 768px to 980px: the rail becomes a horizontal bar under the header, the same
   items in the same order, scrolling sideways when it runs long. */
@media (min-width:768px){
  .nav{ display:block; overflow-x:auto; }
  .nav__list{ display:flex; padding:0; }
  .nav__section{ display:none; }
  .nav__link{
    white-space:nowrap; border-left:0; border-bottom:3px solid transparent;
    padding:var(--sp-3) var(--sp-4);
  }
  .nav__link.is-current{ border-bottom-color:var(--orange); }
  .tabbar{ display:none; }
  body.has-tabbar{ padding-bottom:0; }
  .nav-toggle{ display:none; }
}

/* --bp-md and above: the left rail. */
@media (min-width:981px){
  .app-body{ grid-template-columns:var(--nav-w) 1fr; }
  .nav{ overflow-x:visible; }
  .nav__list{ display:block; padding:var(--sp-3) 0; }
  .nav__section{ display:block; }
  .nav__link{
    white-space:normal; border-bottom:0; border-left:3px solid transparent;
    padding:var(--sp-3) var(--sp-5);
  }
  .nav__link.is-current{ border-left-color:var(--orange); border-bottom-color:transparent; }
  .main{ padding:var(--sp-8) var(--sp-8) var(--sp-12); }
}

/* --------------------------------------------------------------------------
   3. Page title block
   Breadcrumb, optional eyebrow, title, one line of description, the action
   set, then a decorative rule.
   -------------------------------------------------------------------------- */

.titleblock{ margin-bottom:var(--sp-6); }
.crumbs{
  margin:0 0 var(--sp-2);
  font-size:var(--fs-micro); line-height:1.35; color:var(--text-muted);
}
.crumbs a{ color:var(--text-muted); }
.crumbs__sep{ padding:0 var(--sp-1); }
.page-title{ margin:0; }
.page-desc{
  margin:var(--sp-3) 0 0; max-width:var(--maxw-read);
  font-size:var(--fs-body); color:var(--text-body);
  /* A content hash is sixty four characters with nowhere to break, and one of
     these paragraphs carries one. Without this it pushes the page sideways on
     a phone. */
  overflow-wrap:anywhere;
}
.page-actions{ display:flex; flex-direction:column; gap:var(--sp-3); margin-top:var(--sp-5); }
/* Between 768 and 980 the action set is a row under the description rather
   than a stack. STYLE.md pins the two ends of this, right aligned beside the
   title at --bp-md and above and stacked full width below 768px, and a row is
   what the middle asks for: a stacked full width button at 900px reads as a
   banner rather than as an action. */
@media (min-width:768px){
  .page-actions{ flex-direction:row; align-items:center; }
  .page-actions .btn{ width:auto; }
}
.titleblock__rule{
  margin:var(--sp-6) 0 0; border:0; border-top:1px solid var(--border);
}

@media (min-width:981px){
  .titleblock__head{ display:flex; align-items:flex-end; gap:var(--sp-6); }
  .titleblock__head > div:first-child{ flex:1 1 auto; }
  .page-actions{ flex-direction:row; align-items:center; margin-top:0; flex:0 0 auto; }
}

/* --------------------------------------------------------------------------
   4. Cards
   The reference page's module card kept in silhouette and inverted in colour,
   because the page sets white on burnt orange at 2.87:1 and that fails AA.
   -------------------------------------------------------------------------- */

.card{
  background:var(--surface);
  color:var(--text-body);
  border:2px solid var(--border-card);
  border-radius:var(--r-md);
  box-shadow:var(--shadow-card);
  padding:var(--sp-5);
  display:grid;
  /* minmax(0,1fr) rather than auto on the text track. An auto track will not
     go under its own min-content width, and a card that refuses to shrink is
     what puts a horizontal scrollbar on a 320px page. STYLE.md requires the
     page to reflow at 320px with none, so every track and every flex item in
     this component says it may be narrower than its contents. */
  grid-template-columns:38px minmax(0,1fr);
  column-gap:var(--sp-3);
  row-gap:var(--sp-3);
  min-width:0;
  transition:transform var(--t-base), box-shadow var(--t-base), border-color var(--t-base);
}
.card > *{ min-width:0; }
/* A card with no badge is one column. */
.card--nobadge{ grid-template-columns:minmax(0,1fr); }

/* The lift is a promise that something happens on click, so only a card that
   is a link or a button gets it. */
.card--link:hover,
.card--link:focus-within{
  transform:translateY(-5px);
  box-shadow:var(--shadow-hover);
  border-color:var(--orange);
}

.card__badge{
  grid-row:1 / span 2;
  width:38px; height:38px; border-radius:var(--r-round);
  background:var(--forest); color:var(--white);
  display:flex; align-items:center; justify-content:center;
  font-family:var(--display); font-size:1.125rem; line-height:1;
}
.card__title{
  margin:0; min-width:0;
  font-family:var(--body); font-weight:700; font-size:var(--fs-h4);
  line-height:var(--lh-tight); text-transform:uppercase;
  letter-spacing:var(--ls-card-title); color:var(--text-strong);
  overflow-wrap:break-word;
}
.card__title a{ color:inherit; text-decoration:none; }
.card__head{ display:flex; align-items:flex-start; gap:var(--sp-3); min-width:0; flex-wrap:wrap; }
.card__head .chip{ margin-left:auto; flex:0 0 auto; }
.card__body{ font-size:var(--fs-small); line-height:1.5; }
.card__body p{ margin:0 0 var(--sp-3); }
.card__body p:last-child{ margin-bottom:0; }
.card__meta{
  margin:var(--sp-2) 0 0; font-size:var(--fs-micro); line-height:1.35;
  color:var(--text-muted);
}
.card__action{ margin-top:var(--sp-4); }

/* Action card. The orange 4px top rule inside the border, which is the
   treatment the firm's own site uses in its .dlgbrief block. One per view, on
   the single next action. */
.card--action{ border-top:4px solid var(--orange); padding-top:calc(var(--sp-5) - 2px); }

/* Quiet card. Supporting information that is not itself a destination. */
.card--quiet{
  background:var(--surface-alt);
  border:1px solid var(--border);
  box-shadow:none;
}
.card--quiet:hover{ transform:none; border-color:var(--border); box-shadow:none; }

/* Dark card. The reference page's sixth-cell CTA. Once per view at most, and
   in the staff experience that once is the signed confirmation. */
.card--dark{
  background:var(--surface-dark);
  color:var(--text-on-dark);
  border:2px solid var(--orange);
}
.card--dark .card__title{ color:var(--text-on-dark); }
.card--dark .card__meta{ color:var(--text-on-dark-muted); }
.card--dark a{ color:var(--text-on-dark); }

/* One column below 768px, two to 980px, three above. A single card takes the
   reading column rather than sitting alone in a three column grid. */
.card-grid{ display:grid; grid-template-columns:1fr; gap:var(--sp-4); }
.card-grid > *{ min-width:0; }
@media (min-width:768px){ .card-grid{ grid-template-columns:repeat(2,minmax(0,1fr)); } }
@media (min-width:981px){ .card-grid{ grid-template-columns:repeat(3,minmax(0,1fr)); } }
/* A card never sits alone in a three column grid. A single card takes the full
   width of the reading column instead. These two modifiers are declared after
   the queries above on purpose, so they win at every width without needing an
   importance flag. */
.card-grid--solo{ grid-template-columns:minmax(0,1fr); max-width:var(--maxw-read); }
.card-grid--two{ grid-template-columns:minmax(0,1fr); }
@media (min-width:981px){ .card-grid--two{ grid-template-columns:minmax(0,1fr) minmax(0,1.4fr); } }

/* --------------------------------------------------------------------------
   5. Buttons
   Three kinds. 4px radius, --body face, at least --tap tall, no shadow on any
   of them, which is what the reference page does.
   -------------------------------------------------------------------------- */

.btn{
  display:inline-flex; align-items:center; justify-content:center; gap:var(--sp-2);
  min-height:var(--tap); padding:var(--sp-3) var(--sp-5);
  border-radius:var(--r-sm); border:2px solid transparent;
  font-family:var(--body); font-size:var(--fs-body); line-height:1.2;
  text-align:center; text-decoration:none; cursor:pointer;
  background:none; color:var(--text-body);
  transition:background-color var(--t-fast), border-color var(--t-fast), transform var(--t-fast);
}

/* Ink on burnt orange is 5.27:1 and passes. White on it is 3.30:1 and does
   not, which is why this button carries ink even though the reference page
   carries white. One primary button per view is a hard rule. */
.btn--primary{ background:var(--orange); color:var(--ink); border-color:var(--orange); }
.btn--primary:hover{ box-shadow:inset 0 0 0 2px var(--forest); color:var(--ink); }

.btn--secondary{ background:var(--surface); color:var(--forest); border-color:var(--forest); }
.btn--secondary:hover{ background:var(--surface-alt); color:var(--forest); }

.btn--quiet{ padding:var(--sp-3) var(--sp-2); color:var(--forest); }
.btn--quiet:hover{ text-decoration:underline; color:var(--forest); }

.btn:active{ transform:translateY(1px); }

/* Disabled. aria-disabled rather than the attribute wherever the reason has to
   be read out, and a disabled primary always has a line beside it saying what
   would enable it.

   CHANGED from STYLE.md section 5, on Cory's ruling of September 5, 2026.
   STYLE.md sets --silver fill with --text-muted text. Measured on the rendered
   page that pair is --forest-soft on --silver at 3.70:1, which is short of the
   4.5:1 AA bar for normal text. WCAG 2.1 SC 1.4.3 exempts an inactive user
   interface component, but these controls carry aria-disabled rather than the
   disabled attribute, so they stay focusable and reachable by keyboard, and a
   control a person can land on should not lean on that exemption.

   The label takes --text-body instead. --forest on --silver measures 6.80:1.
   The fill, the cursor and the missing hover still carry the state, and the
   line beside the button still says what would open it. No brand rule speaks
   to a disabled state, so nothing here departs from brand.md; the two tokens
   named are the ones already defined for text on a light ground. */
.btn[disabled],
.btn[aria-disabled="true"]{
  background:var(--silver); color:var(--text-body); border-color:var(--silver);
  cursor:not-allowed; box-shadow:none; transform:none;
}
.btn[aria-disabled="true"]:hover{ background:var(--silver); text-decoration:none; }

/* Busy. The label goes to the progressive form and a live region says so. No
   spinner glyph, because the width would jump. */
.btn.is-busy{ cursor:progress; }

.btn-row{ display:flex; flex-direction:column; gap:var(--sp-3); }
.btn-note{
  font-size:var(--fs-small); line-height:1.45; color:var(--text-muted);
  margin:0;
}
.btn-group{ display:flex; flex-direction:column; gap:var(--sp-3); align-items:stretch; }

/* Below 768px a button is full width and centred, and two buttons stack with
   the primary on top. */
@media (max-width:767px){
  .btn{ width:100%; }
  .btn--quiet{ width:auto; }
}
@media (min-width:768px){
  .btn-row{ flex-direction:row; align-items:center; gap:var(--sp-4); flex-wrap:wrap; }
  .btn-group{ flex-direction:row; align-items:center; }
}

/* A filter row of secondary buttons carrying live counts, current one pressed.
   It scrolls sideways on a phone rather than wrapping into a wall. */
.filterbar{
  display:flex; gap:var(--sp-3); overflow-x:auto; padding-bottom:var(--sp-2);
  margin-bottom:var(--sp-5);
}
.filterbar .btn{ width:auto; white-space:nowrap; flex:0 0 auto; padding:var(--sp-2) var(--sp-4); }
/* A search box inside the scrolling filter row. Everything else in the row is
   flex:0 0 auto, so the input is the only thing that can give, and left to
   itself it collapsed to a sliver on a phone and could not be typed in. The
   row still scrolls sideways, which is what it is written to do; the box just
   keeps a width worth having. */
.filterbar .input{ flex:1 1 16rem; min-width:12rem; }
.filterbar .btn[aria-pressed="true"]{ background:var(--forest); color:var(--text-on-dark); border-color:var(--forest); }

/* The segmented control on the phone matrix. Same parts, one visual group. */
.segmented{ display:flex; gap:0; margin-bottom:var(--sp-4); }
.segmented .btn{ border-radius:0; flex:1 1 0; padding:var(--sp-2) var(--sp-3); }
.segmented .btn:first-child{ border-radius:var(--r-sm) 0 0 var(--r-sm); }
.segmented .btn:last-child{ border-radius:0 var(--r-sm) var(--r-sm) 0; }
.segmented .btn[aria-pressed="true"]{ background:var(--forest); color:var(--text-on-dark); border-color:var(--forest); }

/* --------------------------------------------------------------------------
   6. Form fields
   Stacked, never side by side below 768px. The label is a real label and never
   a placeholder.
   -------------------------------------------------------------------------- */

.field{ margin-bottom:var(--sp-4); max-width:var(--maxw-read); }
.field__label{
  display:flex; align-items:baseline; gap:var(--sp-3);
  margin-bottom:var(--sp-2);
  font-family:var(--body); font-weight:700; font-size:var(--fs-small);
  color:var(--text-strong);
}
/* The word "Required", not an asterisk. "Optional" the same way where a form
   mixes both. */
.field__flag{ margin-left:auto; font-weight:400; font-size:var(--fs-micro); color:var(--text-muted); }
.field__help{ margin:var(--sp-2) 0 0; font-size:var(--fs-micro); line-height:1.35; color:var(--text-muted); }

.input,
.select,
.textarea{
  display:block; width:100%;
  min-height:var(--tap);
  padding:var(--sp-3);
  font-family:var(--body); font-size:max(var(--fs-body), var(--tap-input));
  line-height:1.4;
  color:var(--text-strong);
  background:var(--surface);
  /* --border-strong at 5.80:1, never --silver at 1.57:1. An edge nobody can
     see is a field somebody misses. */
  border:1px solid var(--border-strong);
  border-radius:var(--r-sm);
}
.textarea{ min-height:calc(var(--tap) * 2.5); }
.input:focus-visible,
.select:focus-visible,
.textarea:focus-visible{ border-width:2px; padding:calc(var(--sp-3) - 1px); }

/* Error. There is no red in the palette. The border thickens to forest, the
   message says what to do rather than what went wrong, and the ! sits in a
   --bad filled circle so the state is not carried by an edge alone. */
.field--error .input,
.field--error .select,
.field--error .textarea{ border:2px solid var(--forest); padding:calc(var(--sp-3) - 1px); }
.field__error{
  display:flex; align-items:flex-start; gap:var(--sp-2);
  margin:var(--sp-2) 0 0;
  font-size:var(--fs-small); line-height:1.45; color:var(--text-strong);
}
.field__errmark{
  flex:0 0 auto;
  width:20px; height:20px; border-radius:var(--r-round);
  background:var(--bad); color:var(--ink);
  display:inline-flex; align-items:center; justify-content:center;
  font-weight:700; font-size:var(--fs-micro); line-height:1;
}

/* Checkbox and radio. A 24px box, a 2px --border-strong edge, forest when
   checked, and a hit area that covers the box and the whole label text. The
   consent checkbox on the signature panel gets nothing special, because a
   consent control that looks unlike every other control is one somebody ticks
   without reading. */
.check{
  display:flex; align-items:flex-start; gap:var(--sp-3);
  min-height:var(--tap); padding:var(--sp-2) 0;
  cursor:pointer;
}
.check input{
  appearance:none; -webkit-appearance:none;
  flex:0 0 auto; margin:0;
  width:24px; height:24px;
  border:2px solid var(--border-strong); border-radius:var(--r-sm);
  background:var(--surface); cursor:pointer;
  position:relative;
}
.check input[type="radio"]{ border-radius:var(--r-round); }
.check input:checked{ background:var(--forest); border-color:var(--forest); }
/* The tick is drawn from two borders rather than an SVG, so no colour value
   is introduced outside the token block. */
.check input[type="checkbox"]:checked::after{
  content:""; position:absolute; left:6px; top:2px;
  width:6px; height:11px;
  border:solid var(--white); border-width:0 2px 2px 0;
  transform:rotate(45deg);
}
.check input[type="radio"]:checked::after{
  content:""; position:absolute; left:5px; top:5px;
  width:10px; height:10px; border-radius:var(--r-round);
  background:var(--white);
}
.check__text{ font-size:var(--fs-body); line-height:1.45; color:var(--text-body); }

/* --------------------------------------------------------------------------
   7. Tables
   Two shapes. The ordinary list table, and the completion matrix, which is a
   different problem and gets its own answer.
   -------------------------------------------------------------------------- */

.table-note{
  margin:0 0 var(--sp-2);
  font-size:var(--fs-micro); color:var(--text-muted);
}
.table-wrap{ margin-bottom:var(--sp-6); }
.table{ width:100%; border-collapse:collapse; }
.table caption{
  text-align:left; margin-bottom:var(--sp-2);
  font-family:var(--body); font-weight:700; font-size:var(--fs-small);
  color:var(--text-strong);
}
.table th{
  text-align:left; vertical-align:bottom;
  padding:var(--sp-2) var(--sp-3);
  font-family:var(--body); font-weight:700; font-size:var(--fs-micro);
  line-height:1.35; text-transform:uppercase; letter-spacing:var(--ls-eyebrow);
  color:var(--text-muted);
  border-bottom:2px solid var(--border-strong);
}
.table td{
  padding:var(--sp-3);
  font-size:var(--fs-small); line-height:1.45; color:var(--text-body);
  border-bottom:1px solid var(--border);
  vertical-align:top;
}
.table tbody tr{ background:var(--surface); }
.table tbody tr:nth-child(even){ background:var(--surface-alt); }
.table tbody tr.is-link:hover{ background:var(--surface-alt); }
.table a{ color:var(--text-body); }

/* Numbers and dates right aligned and tabular. A missing value is the word
   n/a, never an em dash and never None. The financials stack made that same
   correction once and this copies the corrected version. */
.table .num,
.table th.num{ text-align:right; font-variant-numeric:tabular-nums; }
.na{ color:var(--text-muted); }

/* A sortable header is a th containing a button, with aria-sort on the th, and
   the current sort named in words above the table rather than only by a glyph. */
.sort-btn{
  display:inline-flex; align-items:center; gap:var(--sp-2);
  min-height:var(--tap); padding:0;
  background:none; border:0; cursor:pointer;
  font-family:inherit; font-size:inherit; font-weight:inherit;
  letter-spacing:inherit; text-transform:inherit; color:inherit;
}
.sort-btn:hover{ text-decoration:underline; }
th[aria-sort="ascending"] .sort-btn::after{ content:"\2191"; }
th[aria-sort="descending"] .sort-btn::after{ content:"\2193"; }

/* A second line under a row, for an escalation note or a mailer's own words. */
.row-sub{
  display:block; margin-top:var(--sp-2);
  font-size:var(--fs-micro); line-height:1.35; color:var(--text-muted);
}
.row-actions{ display:flex; gap:var(--sp-3); flex-wrap:wrap; }
.row-actions .btn{ width:auto; }

/* Below 768px every list table becomes stacked row blocks. The header row is
   hidden from sight and kept for assistive technology, each tr is a bordered
   block, and each td is a label and value pair from data-label. */
@media (max-width:767px){
  /* The table stops being a table for LAYOUT here, which is what lets each row
     become a block. It does not stop being a table for MEANING: list_table
     writes the ARIA table roles out in the markup, so a screen reader still
     reads rows and column headers after the display property has taken the
     native semantics away.

     display:block on the table and the body is load bearing and not tidiness.
     Left as a real table, the column algorithm still runs off the widths of
     the hidden header cells, and a five column table then holds the page open
     past 320px no matter what the rows do. Measured on this page: 357px of
     scroll width at a 320px viewport, from one table. */
  .table--stack{ display:block; }
  .table--stack tbody{ display:block; }
  .table--stack thead{
    position:absolute; width:1px; height:1px; padding:0; margin:-1px;
    overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0;
  }
  /* A flex row rather than a block, so the two cells marked as the head can
     share the first line and everything else falls under them at full width.
     The title and the status chip are the two things somebody scans for, so
     they are what the first line carries. */
  .table--stack tbody tr{
    display:flex; flex-wrap:wrap; align-items:baseline;
    margin-bottom:var(--sp-4);
    border:1px solid var(--border); border-radius:var(--r-md);
    padding:var(--sp-3) var(--sp-4);
    background:var(--surface);
  }
  .table--stack tbody tr:nth-child(even){ background:var(--surface); }
  /* A caption inside a block-display table needs telling it is still a line of
     its own, or it lays out as the narrowest thing on the page. */
  .table--stack caption{ display:block; text-align:left; }
  .table--stack td{
    order:2;
    flex:1 1 100%;
    display:flex; gap:var(--sp-3); align-items:baseline;
    padding:var(--sp-2) 0; border-bottom:0;
  }
  .table--stack td::before{
    content:attr(data-label);
    flex:0 0 40%;
    font-family:var(--body); font-weight:700; font-size:var(--fs-micro);
    text-transform:uppercase; letter-spacing:var(--ls-eyebrow);
    color:var(--text-muted);
  }
  /* order rather than DOM order. The head cell and the chip cell are third and
     first in the markup because that is the column order the desktop table
     needs, and the phone needs them together on the first line. Reading order
     for a screen reader still follows the markup, and every other cell in the
     block carries its own label, so the two orders do not disagree about
     anything a reader has to work out. */
  .table--stack td.stack-head{
    order:0;
    display:block;
    flex:1 1 60%;
    font-family:var(--body); font-weight:700; color:var(--text-strong);
  }
  .table--stack td.stack-chip{ order:1; flex:0 0 auto; margin-left:auto; }
  .table--stack td.stack-head .row-sub{ font-weight:400; }
  .table--stack td.stack-head::before,
  .table--stack td.stack-chip::before{ content:none; }
  .table--stack .num{ text-align:left; }
  /* A stacked cell is as wide as the phone and no wider. A 64 character hash,
     an address or a user agent has nowhere to break on its own, so without
     this the cell pushes the whole page sideways and every screen carrying an
     evidence value scrolls horizontally on a phone. min-width:0 is the part
     that is easy to miss: a flex item defaults to the width of its content and
     ignores the wrap rule until it is told it may be narrower than that. */
  .table--stack td{ min-width:0; }
  .table--stack td > *{ min-width:0; overflow-wrap:anywhere; }
  .table--stack td{ overflow-wrap:anywhere; }
}

/* --- The completion matrix ------------------------------------------------
   People down the side and content items across the top is two dimensions, so
   it does not stack. Below 768px it becomes a chooser and a list instead, and
   that change is deliberate rather than a degradation. */

.legend{
  display:flex; flex-wrap:wrap; gap:var(--sp-2) var(--sp-4);
  margin:0 0 var(--sp-4); padding:var(--sp-3) var(--sp-4);
  background:var(--surface-alt); border:1px solid var(--border);
  border-radius:var(--r-sm);
  font-size:var(--fs-micro); color:var(--text-body);
  list-style:none;
}
.legend li{ display:flex; align-items:center; gap:var(--sp-2); }

.matrix-wrap{ overflow:auto; max-height:70vh; border:1px solid var(--border); border-radius:var(--r-sm); }
.matrix{ border-collapse:separate; border-spacing:0; width:100%; }
.matrix th,
.matrix td{ padding:var(--sp-2); text-align:center; }
.matrix thead th{
  position:sticky; top:0; z-index:2;
  background:var(--surface);
  border-bottom:2px solid var(--border-strong);
  font-size:var(--fs-micro); line-height:1.25;
  max-width:96px;
}
.matrix tbody th{
  position:sticky; left:0; z-index:1;
  background:var(--surface);
  text-align:left; white-space:nowrap;
  border-bottom:1px solid var(--border);
  border-right:1px solid var(--border);
  text-transform:none; letter-spacing:normal;
  font-size:var(--fs-small); color:var(--text-body);
}
.matrix thead th:first-child{ left:0; z-index:3; text-align:left; }

/* The style guide's email preview. An email body is a fixed 600px table,
   because that is what a mail client needs, and a fixed 600px table inside a
   390px page is horizontal scroll on the whole page. So the preview gets its
   own scroller and the page still reflows at 320px with none. */
.email-preview{ overflow-x:auto; }
.matrix tbody td{ border-bottom:1px solid var(--border); }
.matrix tbody tr:hover th,
.matrix tbody tr:hover td,
.matrix tbody tr:focus-within th,
.matrix tbody tr:focus-within td{ background:var(--surface-alt); }

/* Each cell is a 20px filled square in the chip's fill with its letter inside,
   plus an aria-label giving the person, the item and the status in words. */
.cellchip{
  display:inline-flex; align-items:center; justify-content:center;
  width:20px; height:20px; border-radius:var(--r-sm);
  font-size:var(--fs-micro); line-height:1;
  color:var(--chip-text); background:var(--chip-assigned);
}
.cellchip--assigned{ background:var(--chip-assigned); }
.cellchip--due-soon{ background:var(--chip-due-soon); }
.cellchip--overdue{ background:var(--chip-overdue); box-shadow:inset 0 0 0 2px var(--chip-edge-overdue); }
.cellchip--complete{ background:var(--chip-complete); }
.cellchip--signed{ background:var(--chip-signed); color:var(--chip-text-inverse); }
/* A dot means the item is not assigned to that person, which is different from
   not done, and it is never coloured. */
.cellchip--none{ background:none; color:var(--text-muted); }
/* Cancelled or superseded on the current cycle. Closed without being done,
   which is a third thing again, and reading it as a dot would report a person
   as never having been asked. */
.cellchip--closed{ background:none; color:var(--text-muted);
                   box-shadow:inset 0 0 0 1px var(--border); }

.matrix-summary{ margin:var(--sp-4) 0 0; font-size:var(--fs-small); color:var(--text-body); }

/* The four counts under the ring on the dashboard. A list in the markup,
   because that is what it is, and a row of tiles on the screen. Without this
   rule it renders as bullet points with the number stuck to the label. */
.countstrip{
  list-style:none; margin:var(--sp-5) 0 0; padding:0;
  display:grid; grid-template-columns:repeat(4, 1fr); gap:var(--sp-3);
}
.countstrip li{
  display:flex; flex-direction:column; align-items:center; gap:var(--sp-1);
  padding:var(--sp-3) var(--sp-2);
  border:1px solid var(--border); border-radius:var(--r-sm);
  background:var(--surface-alt);
  text-align:center;
}
.countstrip span{ font-size:var(--fs-micro); color:var(--text-muted); }
.countstrip b{ font-size:var(--fs-h3); font-weight:700; line-height:1; }
@media (max-width: 599px){
  .countstrip{ grid-template-columns:repeat(2, 1fr); }
}

.matrix-phone__count{ margin:0 0 var(--sp-4); font-size:var(--fs-small); }
.matrix-phone__list{ list-style:none; margin:0 0 var(--sp-5); padding:0; }
.matrix-phone__list li{
  display:flex; align-items:center; justify-content:space-between; gap:var(--sp-3);
  min-height:var(--tap); padding:var(--sp-2) 0;
  border-bottom:1px solid var(--border);
  font-size:var(--fs-small);
}

.matrix-phone{ display:block; }
.matrix-desktop{ display:none; }
@media (min-width:981px){
  .matrix-phone{ display:none; }
  .matrix-desktop{ display:block; }
}

/* --------------------------------------------------------------------------
   8. Status chips
   A pill with the word inside it. The word is not optional: colour never
   carries the meaning on its own, so the chip still reads in greyscale and to
   a reader with a colour vision deficiency.
   -------------------------------------------------------------------------- */

.chip{
  display:inline-flex; align-items:center;
  padding:var(--sp-1) var(--sp-3);
  border-radius:var(--r-pill);
  border:2px solid transparent;
  font-family:var(--body); font-size:var(--fs-micro); line-height:1.35;
  white-space:nowrap;
  background:var(--chip-assigned); color:var(--chip-text);
}
.chip--assigned{ background:var(--chip-assigned); color:var(--chip-text); }  /* ink 11.10:1 */
.chip--due-soon{ background:var(--chip-due-soon); color:var(--chip-text); }  /* ink 10.22:1 */
/* --bad and --orange are the same hex, so without this border an overdue chip
   and a primary button would be the same colour on the same screen. The border
   plus the shape difference, a pill against a 4px rectangle, is what tells
   them apart. This is the weakest seam in the palette and STYLE.md writes it
   down so it is reviewed rather than discovered. */
.chip--overdue{ background:var(--chip-overdue); color:var(--chip-text); border-color:var(--chip-edge-overdue); }  /* ink 5.27:1 */
.chip--complete{ background:var(--chip-complete); color:var(--chip-text); }  /* ink 5.86:1 */
.chip--signed{ background:var(--chip-signed); color:var(--chip-text-inverse); }  /* cream 9.53:1 */
/* "Not yet" is the word on a quiz that did not reach the pass mark. Never
   "failed", on the headline or on the chip. */
.chip--not-yet{ background:var(--chip-due-soon); color:var(--chip-text); }
.chip--closed{ background:var(--surface-alt); color:var(--text-muted); }

/* Review status reuses the completion fills on purpose: two colour languages
   in one app is one too many. A review chip always sits next to the word
   Review or inside a labelled column, so it is never read as an assignment
   status. */
.chip--draft{ background:var(--review-draft); color:var(--chip-text); }
.chip--needs{ background:var(--review-needs); color:var(--chip-text); }
.chip--approved{ background:var(--review-approved); color:var(--chip-text); }

.chip-label{
  display:inline-flex; align-items:center; gap:var(--sp-2);
  font-size:var(--fs-micro); color:var(--text-muted);
}

/* --------------------------------------------------------------------------
   9. Progress indicators
   Three, and each answers a different question. No indeterminate spinner
   anywhere: where the app is waiting it says what it is waiting for, in words,
   in a live region.
   -------------------------------------------------------------------------- */

.progress{ margin-bottom:var(--sp-4); max-width:var(--maxw-read); }
/* The figure in words above the bar. Never the bar alone. */
.progress__label{ display:block; margin-bottom:var(--sp-2); font-size:var(--fs-small); color:var(--text-body); }
/* The bar is drawn as an SVG rather than as a div with a width in a style
   attribute, because DESIGN.md 13.9 sets style-src 'self' with no
   unsafe-inline and a style attribute is exactly what that blocks. The viewBox
   is 100 wide with preserveAspectRatio off, so the fill rect's width attribute
   is the percentage, as a plain SVG attribute that no policy touches. */
.progress__svg{ display:block; width:100%; height:var(--progress-h); }
.progress__track{
  fill:var(--progress-track);
  /* The silver track on a white ground is 1.57:1 and a progress track is a UI
     component that has to clear 3:1, so it carries an outline. */
  stroke:var(--border-strong);
  stroke-width:2;
  vector-effect:non-scaling-stroke;
}
.progress__fill{ fill:var(--progress-fill); transition:width var(--t-base); }

/* Plain text, for the quiz and the signature flow. No dots and no segmented
   bar: a dot row does not say which dot is which and it does not fit ten steps
   on a phone. */
.stepcount{ margin:0 0 var(--sp-3); font-size:var(--fs-micro); color:var(--text-muted); }

/* The ring, dashboard headline only, one per app. The app's one decorative
   flourish, and it earns its place because the dashboard's whole job is to
   answer how much is left. */
.ring{ display:flex; flex-direction:column; align-items:center; gap:var(--sp-2); }
.ring__svg{ width:96px; height:96px; display:block; }
.ring__track{ fill:none; stroke:var(--progress-track); stroke-width:8; }
.ring__arc{
  fill:none; stroke:var(--progress-fill); stroke-width:8; stroke-linecap:round;
  transform:rotate(-90deg); transform-origin:50% 50%;
  transition:stroke-dasharray var(--t-base);
}
.ring__pct{
  font-family:var(--display); font-size:var(--fs-h2); font-weight:700;
  fill:var(--text-strong);
}
.ring__note{ font-size:var(--fs-small); color:var(--text-body); text-align:center; }

/* The count strip on the dashboard and the tiles on admin home. */
.counts{ list-style:none; margin:0 0 var(--sp-6); padding:0; max-width:var(--maxw-read); }
.counts li{
  display:flex; justify-content:space-between; gap:var(--sp-4);
  padding:var(--sp-2) 0; border-bottom:1px solid var(--border);
  font-size:var(--fs-small);
}
.counts li b{ font-variant-numeric:tabular-nums; }

.tiles{ display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:var(--sp-4); margin-bottom:var(--sp-6); }
@media (min-width:981px){ .tiles{ grid-template-columns:repeat(4,minmax(0,1fr)); } }
.tile{
  background:var(--surface-alt); border:1px solid var(--border);
  border-radius:var(--r-md); padding:var(--sp-4);
}
.tile__value{
  display:block; font-family:var(--display); font-size:var(--fs-h2);
  line-height:var(--lh-tight); color:var(--text-strong);
  font-variant-numeric:tabular-nums;
}
.tile__label{ display:block; margin-top:var(--sp-2); font-size:var(--fs-small); color:var(--text-body); }

/* --------------------------------------------------------------------------
   10. Empty states
   Three cases, never merged, because merging them is how an app tells somebody
   a thing is gone when the app simply could not read it.
   -------------------------------------------------------------------------- */

.empty{
  max-width:var(--maxw-read); margin:0 auto var(--sp-6);
  background:var(--surface-alt);
  border:1px solid var(--border); border-radius:var(--r-md);
  padding:var(--sp-6);
  text-align:center;
}
.empty p{ margin:0 0 var(--sp-3); font-size:var(--fs-body); color:var(--text-body); }
.empty p:last-child{ margin-bottom:0; }
.empty .btn{ margin-top:var(--sp-4); }
/* A load failure is never rendered as an empty list. The left rule marks it
   apart at a glance and the wording carries the meaning. --info is a non-text
   role only, which is exactly this. */
.empty--error{ text-align:left; border-left:4px solid var(--info); }
.empty--filtered{ text-align:left; }
/* The best possible state of the overdue screen deserves the shortest possible
   sentence, so it is one line rather than a card. */
.empty-line{ margin:0 0 var(--sp-6); font-size:var(--fs-body); color:var(--text-body); }

/* --------------------------------------------------------------------------
   11. Toasts
   A confirmation of something that already happened. Never a place to put an
   error somebody has to act on: that goes inline, next to the control.
   -------------------------------------------------------------------------- */

.toasts{
  position:fixed; z-index:70;
  left:var(--sp-6); right:var(--sp-6);
  bottom:calc(var(--tabbar-h) + var(--sp-6));
  display:flex; flex-direction:column; gap:var(--sp-3); align-items:center;
  pointer-events:none;
}
.toast{
  pointer-events:auto;
  width:100%; max-width:var(--maxw-read);
  display:flex; align-items:flex-start; gap:var(--sp-3);
  padding:var(--sp-3) var(--sp-4);
  background:var(--surface-dark); color:var(--text-on-dark);
  border-radius:var(--r-md); box-shadow:var(--shadow-modal);
  border-left:4px solid var(--good);
  font-size:var(--fs-small); line-height:1.45;
  transition:transform var(--t-base), opacity var(--t-base);
}
.toast--bad{ border-left-color:var(--bad); }
.toast__msg{ flex:1 1 auto; }
.toast__action,
.toast__dismiss{
  flex:0 0 auto;
  min-height:var(--tap); min-width:var(--tap);
  padding:0 var(--sp-2);
  background:none; border:0; cursor:pointer;
  font-family:var(--body); font-size:var(--fs-small);
  color:var(--text-on-dark); text-decoration:underline;
}
.toast.is-leaving{ opacity:0; transform:translateY(var(--sp-3)); }

@media (min-width:768px){
  .toasts{ left:auto; right:var(--sp-6); bottom:var(--sp-6); align-items:flex-end; width:auto; }
  .toast{ width:auto; min-width:280px; }
}

/* The flash region. Server rendered, present without JavaScript, and it is
   where a message that survives a redirect lands. */
.flash{
  max-width:var(--maxw); margin:0 auto var(--sp-5);
  padding:var(--sp-4);
  background:var(--surface-alt);
  border:1px solid var(--border); border-left:4px solid var(--good);
  border-radius:var(--r-sm);
  font-size:var(--fs-small); color:var(--text-body);
}
.flash--err{ border-left-color:var(--bad); }

/* --------------------------------------------------------------------------
   12. The document reader
   Where staff spend their time, so it gets the most care and the least
   furniture. Three source types, one reading surface.
   -------------------------------------------------------------------------- */

.reader{ display:flex; flex-direction:column; min-height:calc(100vh - var(--header-h)); }

.reader__bar{
  position:sticky; top:var(--header-h); z-index:20;
  background:var(--surface);
  border-bottom:1px solid var(--border);
  padding:var(--sp-3) var(--gutter);
  display:flex; flex-direction:column; gap:var(--sp-2);
}
.reader__back{ font-size:var(--fs-micro); color:var(--text-muted); text-decoration:none; }
.reader__back:hover{ text-decoration:underline; }
.reader__title{
  margin:0;
  font-family:var(--body); font-weight:700; font-size:var(--fs-h4);
  line-height:var(--lh-tight); text-transform:uppercase;
  letter-spacing:var(--ls-card-title); color:var(--text-strong);
}
/* The hash is what makes an acknowledgment mean anything, so it is on the page
   the person read and not only in the evidence record. */
.reader__version{ margin:0; font-size:var(--fs-micro); line-height:1.35; color:var(--text-muted); }
.reader__version code{ font-family:ui-monospace,"Courier New",monospace; }
.reader__version a{ color:var(--text-muted); }

.reader__col{
  flex:1 1 auto;
  background:var(--surface-alt);
  padding:var(--sp-8) var(--gutter);
}
.reader__inner{ max-width:var(--reader-maxw); margin:0 auto; }

.reader__foot{
  position:sticky; bottom:0; z-index:20;
  background:var(--surface);
  border-top:1px solid var(--border);
  padding:var(--sp-3) var(--gutter);
  display:flex; flex-direction:column; gap:var(--sp-3);
}
.reader__condition{ margin:0; font-size:var(--fs-small); color:var(--text-muted); }

@media (min-width:768px){
  .reader__bar{ flex-direction:row; align-items:baseline; gap:var(--sp-4); }
  .reader__bar .reader__title{ flex:1 1 auto; }
  .reader__foot{ flex-direction:row; align-items:center; justify-content:space-between; gap:var(--sp-5); }
  .reader__foot .btn{ width:auto; }
}

/* The prose block. Markdown and DOCX render into exactly this, because the
   DOCX was converted to HTML once at upload. */
.prose{ font-size:var(--fs-body); line-height:var(--reader-lh); color:var(--text-body); }
.prose h2,
.prose h3,
.prose h4{ font-family:var(--display); margin:var(--sp-6) 0 var(--sp-3); text-transform:none; letter-spacing:normal; }
.prose h2{ font-size:var(--fs-h2); line-height:var(--lh-display); }
.prose h3{ font-size:var(--fs-h3); line-height:var(--lh-tight); }
.prose h4{ font-size:var(--fs-h4); line-height:var(--lh-tight); font-weight:700; }
.prose > :first-child{ margin-top:0; }
.prose p{ margin:0 0 var(--sp-4); }
.prose ul,
.prose ol{ margin:0 0 var(--sp-4); padding-left:var(--sp-6); }
.prose li{ margin-bottom:var(--sp-2); }
.prose blockquote{
  margin:0 0 var(--sp-4); padding:var(--sp-4);
  border-left:4px solid var(--orange);
  background:var(--surface);
}
.prose table{ width:100%; border-collapse:collapse; margin:0 0 var(--sp-4); }
.prose th{
  text-align:left; padding:var(--sp-2) var(--sp-3);
  font-size:var(--fs-micro); text-transform:uppercase;
  letter-spacing:var(--ls-eyebrow); color:var(--text-muted);
  border-bottom:2px solid var(--border-strong);
}
.prose td{ padding:var(--sp-3); font-size:var(--fs-small); border-bottom:1px solid var(--border); }

/* The end-of-document sentinel the IntersectionObserver watches. It has no
   look of its own. */
.reader__sentinel{ display:block; height:1px; }

/* PDF. The browser's own viewer does the work: the app ships no PDF renderer.
   The fallback is built first and treated as the real path, because it is the
   path a phone often takes, and the inline frame is the enhancement. */
.pdfframe{
  display:block; width:100%; height:var(--reader-pdf-h);
  border:1px solid var(--border-strong); border-radius:var(--r-sm);
  background:var(--surface);
}
.pdf-fallback{
  max-width:var(--maxw-read); margin:0 auto;
  background:var(--surface); border:1px solid var(--border);
  border-radius:var(--r-md); padding:var(--sp-6);
}
.pdf-fallback .btn-row{ margin-top:var(--sp-4); }

/* --------------------------------------------------------------------------
   13. The quiz card
   One question to a screen, at full reading width, no badge.
   -------------------------------------------------------------------------- */

.quiz{ max-width:var(--maxw-read); }
.quiz__question{ margin:0 0 var(--sp-5); font-family:var(--display); font-size:var(--fs-h3); line-height:var(--lh-tight); }
.options{ list-style:none; margin:0 0 var(--sp-5); padding:0; }
.options li{ margin-bottom:var(--sp-3); }

/* The whole row is the label, so the whole row is the hit area. Options are
   keyboard reachable as a native radio group with arrow keys, which is another
   reason not to rebuild the control. */
.option{
  display:flex; align-items:flex-start; gap:var(--sp-3);
  padding:var(--sp-4);
  border:1px solid var(--border-strong); border-radius:var(--r-sm);
  background:var(--surface); cursor:pointer;
  min-height:var(--tap);
}
.option input{
  appearance:none; -webkit-appearance:none;
  flex:0 0 auto; margin:0; position:relative;
  width:24px; height:24px;
  border:2px solid var(--border-strong); border-radius:var(--r-round);
  background:var(--surface); cursor:pointer;
}
.option input:checked{ background:var(--forest); border-color:var(--forest); }
.option input:checked::after{
  content:""; position:absolute; left:5px; top:5px;
  width:10px; height:10px; border-radius:var(--r-round); background:var(--white);
}
.option:has(input:checked){ border:2px solid var(--forest); background:var(--surface-alt); padding:calc(var(--sp-4) - 1px); }
.option__text{ font-size:var(--fs-body); line-height:1.45; color:var(--text-body); }

/* The four rules, stated before the first question, so nobody is guessing. */
.quiz-rules{ max-width:var(--maxw-read); }
.quiz-rules ul{ margin:0 0 var(--sp-4); padding-left:var(--sp-6); font-size:var(--fs-body); }

/* The result panel is a full screen and not a modal, so the coaching has room. */
.result__score{ margin:var(--sp-3) 0 0; font-family:var(--display); font-size:var(--fs-h3); color:var(--text-strong); }
.result__lede{ max-width:var(--maxw-read); margin:var(--sp-5) 0; }
.result-cards{ display:grid; gap:var(--sp-4); max-width:var(--maxw-read); margin-bottom:var(--sp-6); }
.answer-pair{ list-style:none; margin:var(--sp-3) 0; padding:0; font-size:var(--fs-small); }
.answer-pair div{ display:flex; gap:var(--sp-3); margin-bottom:var(--sp-2); }
.answer-pair dt{ flex:0 0 34%; font-weight:700; color:var(--text-strong); }
.answer-pair dd{ margin:0; }

/* --------------------------------------------------------------------------
   14. The signature panel
   The last screen before a signature, and the one that has to be unambiguous.
   It takes the action card treatment at the one moment in the app where that
   treatment belongs most.
   -------------------------------------------------------------------------- */

.sigpanel{
  max-width:var(--maxw-read);
  background:var(--surface);
  border:2px solid var(--border-card);
  border-top:4px solid var(--orange);
  border-radius:var(--r-md);
  padding:var(--sp-6);
}
.sigpanel__heading{ margin:0 0 var(--sp-5); font-size:var(--fs-h2); }
/* What the person is signing, stated before the controls rather than after
   them. */
.sigpanel__version{
  background:var(--surface-alt); border:1px solid var(--border);
  border-radius:var(--r-sm); padding:var(--sp-4);
  margin-bottom:var(--sp-5);
}
.sigpanel__version dl{ margin:0; font-size:var(--fs-small); }
.sigpanel__version div{ display:flex; gap:var(--sp-3); margin-bottom:var(--sp-2); }
.sigpanel__version div:last-child{ margin-bottom:0; }
.sigpanel__version dt{ flex:0 0 34%; color:var(--text-muted); }
.sigpanel__version dd{ margin:0; color:var(--text-strong); }
.sigpanel__hash{ font-family:ui-monospace,"Courier New",monospace; font-size:var(--fs-micro); word-break:break-all; }

/* The echo. The one place display type carries something a person entered. It
   gives the act some weight without pretending to be a handwritten signature.
   A drawn signature is out of release 1 and no space is left for it here. */
.sig-echo{
  min-height:calc(var(--fs-h3) * 1.6);
  margin:var(--sp-4) 0 var(--sp-5);
  padding:var(--sp-3) 0;
  border-bottom:1px solid var(--border);
  font-family:var(--display); font-size:var(--fs-h3); line-height:1.4;
  color:var(--text-strong);
}
/* A soft check against the profile name warns and never blocks. A person whose
   legal name differs from their directory name is a real case and the app does
   not get to argue with them about it. */
.sig-warn{ margin:var(--sp-2) 0 0; font-size:var(--fs-small); line-height:1.45; color:var(--text-strong); }
.sig-warn[hidden]{ display:none; }
/* Nobody signs a thing without being told what the signature captures. */
.sig-records{ margin:0 0 var(--sp-5); font-size:var(--fs-small); line-height:1.5; color:var(--text-muted); }

/* --------------------------------------------------------------------------
   15. Sign in, the only unauthenticated screen
   --surface-deep is reserved for this screen and nothing else. It reads as the
   door rather than as a page of the app.
   -------------------------------------------------------------------------- */

/* The one screen with no fixed header, so it also has no room to leave for
   one. Without this the body padding that clears the header on every other
   screen shows as a white band above the door. */
body.signin-page{ padding-top:0; background:var(--surface-deep); }

.signin{
  min-height:100vh;
  background:var(--surface-deep); color:var(--text-on-dark);
  display:flex; flex-direction:column; align-items:center; justify-content:center;
  gap:var(--sp-5); padding:var(--sp-10) var(--gutter);
  text-align:center;
}
.signin h1{ margin:0; color:var(--text-on-dark); }
.signin__lede{ margin:0; color:var(--text-on-dark-muted); }
.signin__card{
  width:100%; max-width:var(--maxw-read);
  background:var(--surface); color:var(--text-body);
  border:2px solid var(--border-card); border-radius:var(--r-md);
  padding:var(--sp-6);
}
.signin__help{ margin:0; font-size:var(--fs-micro); color:var(--text-on-dark-muted); }
.signin .wordmark{ text-align:center; }

/* --------------------------------------------------------------------------
   16. Two small shapes the screens name
   -------------------------------------------------------------------------- */

/* The identity strip on a training record. */
.identity{
  margin:0 0 var(--sp-6); padding:0 0 var(--sp-4);
  border-bottom:1px solid var(--border);
  font-size:var(--fs-small); color:var(--text-body);
}
.identity strong{ color:var(--text-strong); }

/* One line of plain-word summary above a list. */
.summary-line{ margin:0 0 var(--sp-5); font-size:var(--fs-body); color:var(--text-body); }

/* A recent-activity list: a time, then what happened. */
.activity{ list-style:none; margin:0 0 var(--sp-4); padding:0; }
.activity li{
  display:flex; gap:var(--sp-4); padding:var(--sp-2) 0;
  border-bottom:1px solid var(--border); font-size:var(--fs-small);
}
.activity time{ flex:0 0 22%; color:var(--text-muted); font-variant-numeric:tabular-nums; }

/* The style guide, and nowhere else. It shows the reader's sticky header and
   sticky footer outside the screen they belong to, where sticky has the whole
   document to stick to and the bar follows the reader down every section. This
   pins them where they are drawn. */
.sg-unstick .reader__bar,
.sg-unstick .reader__foot{ position:static; }

/* --------------------------------------------------------------------------
   17. Reduced motion
   Under prefers-reduced-motion the card lift, the badge inversion, the toast
   slide and the progress fill all stop. The reference page honours none of
   this, and an internal tool people use daily should.
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion:reduce){
  html{ scroll-behavior:auto; }
  *,*::before,*::after{
    animation-duration:0.01ms !important;
    animation-iteration-count:1 !important;
    transition-duration:0.01ms !important;
    scroll-behavior:auto !important;
  }
  .card--link:hover,
  .card--link:focus-within{ transform:none; }
  .btn:active{ transform:none; }
  .toast.is-leaving{ transform:none; }
}

/* --------------------------------------------------------------------------
   18. Print, for the training record
   A record somebody prints is a record somebody files, so the chrome goes and
   the three tables run at full width with their headings repeated. Colour is
   not relied on: every chip already carries its word.
   -------------------------------------------------------------------------- */

@media print{
  :root{ --fs-body:11pt; --fs-small:10pt; --fs-micro:9pt; --fs-h1:18pt; --fs-h2:14pt; --fs-h3:12pt; }
  body{ padding-top:0; background:var(--white); color:var(--ink); }
  .app-header,
  .nav,
  .nav-panel,
  .nav-scrim,
  .tabbar,
  .toasts,
  .skip-link,
  .page-actions,
  .filterbar,
  .btn,
  .row-actions{ display:none !important; }
  .app-body{ display:block; }
  .main{ padding:0; }
  .page{ max-width:none; }
  .card,
  .empty,
  .table-wrap{ break-inside:avoid; box-shadow:none; }
  .table{ width:100%; }
  .table thead{ display:table-header-group; }
  .table tbody tr{ break-inside:avoid; background:var(--white) !important; }
  .table td,
  .table th{ border-color:var(--ink); }
  .chip{ border:1px solid var(--ink); background:var(--white) !important; color:var(--ink) !important; }
  /* The footer's internal-draft line prints. It is the one piece of chrome
     that has to survive onto paper, because a page off a printer with no
     provenance on it is a page somebody treats as final. */
  .app-footer{ padding:var(--sp-6) 0 0; }
  .app-footer p{ color:var(--ink); }
  a[href]::after{ content:""; }
}
