:root{
  --paper:#EDF0EF;
  --card:#F7F9F8;
  --ink:#141C1A;
  --wire:#6E7C79;
  --indigo:#2C3E70;
  --clay:#B5651D;
  --rule:rgba(20,28,26,.14);
  /* The hairline the light pages are drawn with, inverted for the dark bands.
     Same idea, same weight, legible against ink instead of paper. */
  --rule-dk:rgba(237,240,239,.18);
  --sans:"IBM Plex Sans",ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,sans-serif;
  --mono:"IBM Plex Mono",ui-monospace,SFMono-Regular,Menlo,monospace;
  /* Headings are set in a serif — the practice is a clinic, not a console, and
     a page that opens in the same face as its data tables reads as a report.
     Source Serif is a reading face rather than a display one, so it holds up
     at 15px in a card as well as at 50px in the hero. */
  --serif:"Source Serif 4",Iowan Old Style,Palatino,Georgia,serif;
  /* The face on the practice's own board and invitation: a high-contrast
     display serif, set in caps with the first letter of each word larger. It
     is the brand's voice rather than the site's, so it is used for the name,
     the home page's headings and the sentences those headings introduce —
     never for anything a doctor has to read a column of. */
  --display:"Playfair Display",Didot,"Bodoni MT",Georgia,serif;
  /* The cream the signboard is lit in, and the ground it hangs on. These are
     to the home page what --card and --paper are to the clinical ones — the
     same two steps of tone, warmed. The pairs never meet: a page is on one or
     the other, and only the home page is on these. */
  --ivory:#FBF8F1;
  --sand:#F2EEE4;
  /* The gutter between two table columns. One value for the whole site: a
     column of digits reads as a column because nothing else is near it, and
     every table here had been setting its own gap — or none — per cell. */
  --gut:22px;
}
*{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{
  margin:0;background:var(--paper);color:var(--ink);
  font-family:var(--sans);font-size:15.5px;line-height:1.55;
  -webkit-font-smoothing:antialiased;
}
a{color:inherit}

/* ---------------------------------------------------------- masthead -- */
.masthead{
  max-width:1000px;margin:0 auto;padding:20px 24px 18px;
  display:flex;justify-content:space-between;align-items:baseline;gap:20px;
  border-bottom:1px solid var(--rule);flex-wrap:wrap;
}
/* The name is set the way the board on Brigade Road sets it — display serif,
   caps, widely tracked — rather than in the monospace the nav beside it uses.
   It is the one piece of the masthead that is the practice rather than the
   site, and it should read as the same object on every page. */
.wordmark{
  display:flex;align-items:center;gap:11px;
  font-family:var(--display);font-size:15px;font-weight:500;letter-spacing:.14em;
  text-transform:uppercase;text-decoration:none;color:var(--ink);
}
/* The logo artwork is white-on-black by design, so it sits on its own dark
   tile rather than being recoloured — recolouring flattened the tooth's
   pale-cyan crown and the grey brackets to a single flat tone. */
.wordmark img{
  display:block;height:30px;width:auto;background:#000;
  border-radius:3px;padding:4px 6px;
}

.masthead nav a.book{
  color:var(--indigo);border:1px solid var(--indigo);border-radius:2px;
  padding:6px 13px;margin-left:2px;
}
.masthead nav a.book:hover{background:var(--indigo);color:#fff;border-color:var(--indigo)}
.masthead nav{display:flex;align-items:center;gap:22px}
.masthead nav a{
  font-family:var(--mono);font-size:11px;letter-spacing:.13em;
  text-transform:uppercase;text-decoration:none;color:var(--wire);
  padding-bottom:2px;border-bottom:1px solid transparent;
}
.masthead nav a:hover{color:var(--ink)}
.masthead nav a.on{color:var(--ink);border-bottom-color:var(--indigo)}

/* ----------------------------------------------------------- account -- */
/* Portraits. Round, and cropped square from whatever Drive returns — the
   profile photographs are not shot to any one ratio. */
.avatar{
  display:block;flex:0 0 auto;border-radius:50%;object-fit:cover;
  background:var(--card);border:1px solid var(--rule);
}
.avatar.sm{width:30px;height:30px}
.avatar.lg{width:124px;height:124px}
/* Doctors are staff and have no photograph on file, so initials stand in. */
.avatar.mono{
  display:flex;align-items:center;justify-content:center;
  font-family:var(--mono);font-size:11px;letter-spacing:.02em;color:var(--wire);
}

.acct{position:relative}
.acct summary{display:block;list-style:none;cursor:pointer;border-radius:50%}
.acct summary::-webkit-details-marker{display:none}
.acct summary:hover .avatar,.acct[open] summary .avatar{border-color:var(--indigo)}
.acct summary:focus-visible{outline:2px solid var(--indigo);outline-offset:3px}

.acct-menu{
  position:absolute;right:0;top:calc(100% + 14px);z-index:20;min-width:214px;
  background:var(--card);border:1px solid var(--rule);border-radius:3px;
  box-shadow:0 14px 34px rgba(20,28,26,.16);padding:6px;
}
.acct-who{margin:0;padding:11px 12px 13px;border-bottom:1px solid var(--rule)}
.acct-who b{
  display:block;font-family:var(--sans);font-size:14px;font-weight:500;
  letter-spacing:-.01em;color:var(--ink);text-transform:none;
}
.acct-who span{
  display:block;font-family:var(--mono);font-size:10px;letter-spacing:.08em;
  color:var(--wire);margin-top:4px;word-break:break-all;
}
/* The nav's own link styling is for a row of section names; these are menu
   rows, so they lose the underline and take the full width of the panel. */
.masthead nav .acct-menu a{display:block;padding:10px 12px;border-bottom:0}
.masthead nav .acct-menu a:hover{background:var(--paper);color:var(--ink)}
.masthead nav .acct-menu a.on{color:var(--ink)}
/* The sections above are places to go; signing out is not one of them. */
.masthead nav .acct-menu a.acct-out{
  margin-top:6px;padding-top:13px;border-top:1px solid var(--rule);
}

/* ------------------------------------------------------------ layout -- */
.wrap{max-width:1000px;margin:0 auto;padding:0 24px 80px}
.wrap.narrow{max-width:620px}
h1{
  font-family:var(--serif);font-size:clamp(32px,5vw,50px);font-weight:400;
  letter-spacing:-.012em;margin:52px 0 10px;line-height:1.08;
}
/* Section headings are labels rather than titles — small, spaced, and set
   against a hairline that runs to the edge of the column, so a section reads
   as beginning even before its words are. */
h2{
  font-family:var(--mono);font-size:11px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--wire);font-weight:400;
  margin:64px 0 20px;display:flex;align-items:center;gap:16px;
}
h2:after{content:"";flex:1 1 auto;height:1px;background:var(--rule)}
.lede{font-size:19px;line-height:1.6;color:var(--wire);max-width:58ch;margin:0 0 34px}
.lede b{color:var(--ink);font-weight:500}

.foot{
  max-width:1000px;margin:0 auto;padding:22px 24px 40px;
  border-top:1px solid var(--rule);display:flex;justify-content:space-between;
  gap:10px 26px;flex-wrap:wrap;
  font-family:var(--mono);font-size:11px;letter-spacing:.08em;color:var(--wire);
}
.foot a{text-decoration:none}
.foot a:hover{color:var(--ink)}

/* -------------------------------------------------------------- home -- */
/* The home page answers to the practice's signage rather than to the rest of
   the site. The board on Brigade Road is white on black, mounted on dark
   fluted panelling, and the name is set in a display serif with the first
   letter of each word raised; the invitation puts the same lockup inside a lit
   cream arch. So this page opens and closes on ink with the panelling behind
   it, and the name arrives in an arch of its own rather than as a picture.
   Everything below is scoped to .hero, .closer or body.public — the clinical
   pages keep the quieter furniture they are read with. */
.hero,.closer{background:var(--ink);color:var(--paper);position:relative;overflow:hidden}
/* The panelling. Not pinstripes: the wall behind the board is fluted, battens
   standing off it with a shadowed groove between, and a batten is a rounded
   face rather than a flat one. So each 34px is a groove, the lit near edge of
   the next batten, its face falling away, and the shadow gathering again — the
   gradient between those stops is what gives the flute its roundness. 34px
   because it puts about a dozen battens across the arch, which is how many
   stand behind the board in the photograph.

   The light is warm rather than white, since the only light in this room comes
   off the sign and the two sconces beside it. */
.hero:before,.closer:before{
  content:"";position:absolute;inset:0;pointer-events:none;
  background:repeating-linear-gradient(90deg,
    rgba(0,0,0,.5) 0 4px,
    rgba(255,250,240,.075) 7px 9px,
    rgba(255,250,240,.03) 14px 21px,
    rgba(255,250,240,.006) 29px 34px);
}
/* The wash a lit sign throws onto the wall behind it, sitting under the arch
   and reaching past its edges. */
.hero:after{
  content:"";position:absolute;top:50%;right:12%;width:660px;height:660px;
  transform:translateY(-50%);pointer-events:none;
  background:radial-gradient(closest-side,rgba(255,238,206,.17),transparent 70%);
}
.hero-in,.closer-in{max-width:1000px;margin:0 auto;padding:0 24px;position:relative}

.hero-in{
  display:grid;grid-template-columns:1.05fr .95fr;gap:56px;align-items:center;
  padding-top:64px;padding-bottom:72px;
}

/* The lit arch. Typeset rather than an image of the board: the artwork is
   white on solid black with no transparency, so on any ground but its own it
   arrives as a black tile — and the name, the doctor and her qualification are
   words a reader and a screen reader should both get. The top radius is half
   the arch's width, which is what makes it a semicircle rather than a rounded
   rectangle, and the padding above the name is the room that curve takes. */
.arch{
  justify-self:end;width:100%;max-width:390px;
  background:linear-gradient(180deg,#FCFAF4 0%,#F1ECE0 100%);
  color:#0F1413;text-align:center;
  border-radius:195px 195px 5px 5px;
  padding:82px 34px 42px;
  box-shadow:0 0 0 1px rgba(255,248,232,.45),
             0 0 80px rgba(255,235,193,.30),
             0 30px 64px rgba(0,0,0,.42);
}
/* JACOBS, and DENTAL STUDIO under it: caps throughout, with the first letter
   of each word set larger, which is how the board is lettered. */
.arch-name{
  font-family:var(--display);font-weight:600;font-size:clamp(40px,5.6vw,58px);
  line-height:.92;letter-spacing:.015em;text-transform:uppercase;margin:0;
}
.arch-sub{
  font-family:var(--display);font-weight:600;font-size:clamp(16px,2.1vw,21px);
  letter-spacing:.1em;text-transform:uppercase;margin:10px 0 0;
}
/* The raised first letter of a word in the name, wherever the name is set. */
.cap{font-size:1.29em;font-weight:inherit;line-height:1}
.arch-tooth{display:block;width:104px;height:auto;margin:20px auto 0}
.arch-dr{font-family:var(--display);font-size:21px;font-weight:500;margin:0}
.arch-dr .quals{
  font-family:var(--mono);font-size:9.5px;letter-spacing:.1em;
  vertical-align:.42em;color:rgba(15,20,19,.62);white-space:nowrap;
}
.arch-spec{
  font-family:var(--mono);font-size:9.5px;letter-spacing:.13em;line-height:1.6;
  text-transform:uppercase;color:rgba(15,20,19,.6);margin:9px 0 0;
}

/* The rule with a dot in the middle of it, off the invitation. Takes its
   colour from whatever it sits in, so the same ornament works on cream and on
   ink without a second rule for the dark bands. */
.orn{display:flex;align-items:center;justify-content:center;gap:14px;margin:22px 0}
.orn:before,.orn:after{
  content:"";height:1px;flex:0 1 74px;background:currentColor;opacity:.32;
}
.orn i{
  display:block;flex:0 0 auto;width:5px;height:5px;border-radius:50%;
  background:currentColor;opacity:.75;
}

/* The headline is the brand's face too, at the one size on the page that can
   carry it. */
.hero h1{
  font-family:var(--display);font-weight:400;font-size:clamp(34px,4.7vw,54px);
  line-height:1.06;letter-spacing:-.005em;
  margin:0 0 18px;color:var(--paper);max-width:14ch;
}
.hero .lede{color:rgba(237,240,239,.72);max-width:46ch;margin:0 0 30px;font-size:18px}
.hero .kicker,.closer .kicker{
  font-family:var(--mono);font-size:11px;letter-spacing:.16em;
  text-transform:uppercase;color:var(--clay);margin:0 0 14px;
}
/* On ink, an outlined indigo button disappears. These read in paper instead,
   and the filled one inverts: the page's brightest surface as its loudest
   thing to press. */
.hero .tools a,.closer .tools a{border-color:var(--rule-dk);color:var(--paper)}
.hero .tools a:hover,.closer .tools a:hover{background:rgba(237,240,239,.1);color:#fff}
.hero .tools a.primary,.closer .tools a.primary{
  background:var(--paper);color:var(--ink);border-color:var(--paper);
}
.hero .tools a.primary:hover,.closer .tools a.primary:hover{background:#fff;border-color:#fff}

.closer-in{
  display:flex;align-items:center;justify-content:space-between;gap:40px;
  flex-wrap:wrap;padding-top:52px;padding-bottom:56px;
}
.closer .say{
  font-family:var(--display);font-size:24px;font-weight:400;line-height:1.42;
  margin:0;max-width:34ch;color:var(--paper);
}
.closer .tools{margin-top:0}
/* The page signs off the way the board is lettered: the tooth, and beside it
   the name and whose practice it is. Ruled off from the call to action above
   it, because it is not another thing to do — it is the signature under the
   ones that are, and it is centred rather than spanning the column for the
   same reason a signature is not a row of headings. */
.closer-sign{
  position:relative;max-width:1000px;margin:0 auto;padding:30px 24px 46px;
  border-top:1px solid var(--rule-dk);
  display:flex;align-items:center;justify-content:center;
  gap:22px;flex-wrap:wrap;
}
.closer-sign p{margin:0}
.sign-mark{display:block;width:auto;height:66px;mix-blend-mode:screen}
.sign-name{
  font-family:var(--display);font-size:19px;font-weight:600;letter-spacing:.15em;
  text-transform:uppercase;color:var(--paper);
}
.sign-say .sign-dr{margin-top:9px;font-size:15px;font-weight:500;color:var(--paper)}
.sign-dr .quals,.sign-spec{
  font-family:var(--mono);font-size:9.5px;letter-spacing:.12em;
  text-transform:uppercase;color:rgba(237,240,239,.55);
}
.sign-say .sign-spec{margin-top:4px;line-height:1.6}
/* On a page with no call to action of its own, the signature is the whole
   band, so the rule it hangs under would be a line across the top of it. */
.closer > .closer-sign:first-child{border-top:0;padding-top:44px}
/* The footer's own rule would sit a hairline under the dark band and read as a
   second edge to it. The band is the division already. */
.closer + .foot{border-top:0}

/* ----------------------------------------------------- public pages -- */
/* The light half of every page a patient sees: the home page between its two
   dark bands, and Results, Contact, sign in and register whole. It keeps the
   site's column and hairlines and changes only what the signage speaks to —
   the ground it is lit on, and the face its headings are set in.

   The two surfaces are swapped once, here, rather than component by
   component: --paper and --card are what every card, panel, field, table rule
   and map on the site is drawn with, so redefining them on <body> lights the
   whole public half warm and leaves the clinical pages on the cool pair they
   are read with. All of it hangs off the class page_head() puts on <body>, so
   a clinical page cannot pick any of it up by using the same furniture. */
body.public{--paper:var(--sand);--card:var(--ivory)}

/* Titles are the brand's face at the size that can carry it. */
.public h1{font-family:var(--display);font-weight:400;letter-spacing:-.005em}

/* Section headings on the clinical pages are monospace labels. Here they are
   the brand's caps, with a dot in place of the rule's left end — the same
   ornament the arch uses, at the size a heading can carry. */
.public h2{
  font-family:var(--display);font-size:13px;font-weight:500;letter-spacing:.22em;
  color:var(--ink);gap:13px;margin-top:74px;
}
.public h2:before{
  content:"";flex:0 0 auto;width:5px;height:5px;border-radius:50%;
  background:var(--clay);
}
.public .lede.sm{font-size:16.5px;max-width:62ch}

/* Three lit arches rather than three square cards: the same shape the name
   sits in above, at a third of the width. Centred, because an arch has a
   middle and text ranged left in one ignores it. The home page only — the
   arch is what that page opens on, and three of them on every page would be
   wallpaper rather than a signboard.

   The radius is elliptical — the full half-width across, a good deal less down
   — because a card is a third as tall as the sign is. A true semicircle on a
   box this shape is nearly all dome, and the first line of type ends up
   stranded halfway down it. */
.home .cols{gap:20px;margin-top:6px}
.home .cols section{
  border-radius:150px 150px 4px 4px / 86px 86px 4px 4px;
  padding:44px 30px 34px;text-align:center;
  transition:transform .18s ease,box-shadow .18s ease;
}
.home .cols section:hover{
  transform:translateY(-3px);box-shadow:0 18px 36px rgba(20,28,26,.10);
}
.home .cols .num{
  font-family:var(--display);font-size:13px;letter-spacing:.2em;
  color:var(--clay);margin-bottom:15px;
}
.home .cols h3{
  font-family:var(--display);font-size:23px;font-weight:500;margin-bottom:12px;
}
.home .cols p{max-width:31ch;margin:0 auto}

/* The figures keep the dashboard's grid and gain the public pages' face — the
   count is a statement here, not a cell. */
.public .figures > div{text-align:center;padding:24px 18px 26px}
.public .figures dd{font-family:var(--display);font-size:46px;font-weight:400}
.public .figures dt{letter-spacing:.16em}

.public .split .say{font-family:var(--display);font-size:21px;line-height:1.5}

/* Three cards rather than three columns divided by hairlines: a card gives the
   heading room to sit above its own paragraph instead of against the rule of
   the one beside it. */
.cols{display:grid;grid-template-columns:repeat(3,1fr);gap:18px;margin-top:4px}
.cols section{
  background:var(--card);border:1px solid var(--rule);border-radius:3px;
  padding:28px 26px 30px;
}
.cols h3{font-family:var(--serif);font-size:21px;font-weight:600;margin:0 0 10px;
  letter-spacing:-.005em;line-height:1.25}
.cols p{margin:0;color:var(--wire);font-size:14.5px;line-height:1.6}
.cols .num{
  font-family:var(--mono);font-size:11px;color:var(--indigo);
  letter-spacing:.1em;display:block;margin-bottom:18px;
}

.split{display:grid;grid-template-columns:1.15fr 1fr;gap:56px;align-items:start}
.split p{margin:0 0 16px;max-width:52ch}
/* The opening sentence of a section, set larger and in the serif so the eye
   has somewhere to land before the body text. */
.split .say{
  font-family:var(--serif);font-size:20px;line-height:1.5;color:var(--ink);
  margin-bottom:20px;
}
.factlist{border-top:1px solid var(--rule);margin:0}
.factlist div{
  display:flex;justify-content:space-between;gap:18px;padding:13px 2px;
  border-bottom:1px solid var(--rule);
}
.factlist dt{font-family:var(--mono);font-size:11px;letter-spacing:.12em;text-transform:uppercase;color:var(--wire)}
.factlist dd{margin:0;font-size:14.5px;text-align:right}

.tools{display:flex;gap:14px;flex-wrap:wrap;margin-top:18px}
.tools a{
  font-family:var(--mono);font-size:12px;letter-spacing:.08em;text-decoration:none;
  border:1px solid var(--indigo);color:var(--indigo);padding:11px 19px;border-radius:2px;
}
.tools a:hover{background:var(--indigo);color:#fff}
.tools a.primary{background:var(--indigo);color:#fff}
.tools a.primary:hover{background:var(--ink);border-color:var(--ink)}

/* address + map */
.address{
  font-family:var(--mono);font-size:14px;line-height:1.8;color:var(--ink);
  margin:0 0 18px;
}
.mapcard{
  display:block;text-decoration:none;border:1px solid var(--rule);
  border-radius:2px;overflow:hidden;background:var(--card);
}
.mapcard iframe{display:block;width:100%;height:260px;border:0;filter:saturate(.75)}
.mapcard span{
  display:block;padding:12px 14px;border-top:1px solid var(--rule);
  font-family:var(--mono);font-size:11.5px;letter-spacing:.06em;color:var(--wire);
}
.mapcard:hover span{color:var(--ink)}

/* ---------------------------------------------------------- controls -- */
.pickers{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:20px;margin:8px 0 4px}
.field label{
  display:block;font-family:var(--mono);font-size:10px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--wire);margin-bottom:7px;
}
select,input[type=password]{
  width:100%;font-family:var(--sans);font-size:15px;color:var(--ink);
  background:var(--card);border:1px solid var(--rule);border-radius:2px;
  padding:11px 12px;appearance:none;
}
select:focus,input:focus{outline:2px solid var(--indigo);outline-offset:-1px}
select:disabled{color:var(--wire);background:transparent}

.signin{margin-top:26px;max-width:340px}
.signin label{
  display:block;font-family:var(--mono);font-size:10px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--wire);margin:0 0 7px;
}
.signin label + input{margin-bottom:18px}
/* Every kind of field the site asks for, styled once. The type list is not
   decoration: an input styled only as [type=text] loses the border and the
   paper the moment a form asks for an email address, which is exactly what the
   enquiry form does three fields in. */
.signin input[type=text],
.signin input[type=email],
.signin input[type=tel],
.signin textarea{
  width:100%;font-family:var(--sans);font-size:15px;color:var(--ink);
  background:var(--card);border:1px solid var(--rule);border-radius:2px;
  padding:11px 12px;
}
.signin textarea{
  display:block;line-height:1.55;margin-bottom:18px;
  /* Vertical only: a textarea dragged wider than its column breaks the two-up
     layout it sits in, and there is nothing to gain by it. */
  resize:vertical;min-height:150px;
}
.signin button{
  margin-top:14px;font-family:var(--mono);font-size:12px;letter-spacing:.1em;
  background:var(--indigo);color:#fff;border:0;border-radius:2px;
  padding:12px 22px;cursor:pointer;
}
/* The username on the password step is shown back, not re-editable — it was
   settled by the previous step and the hidden field is what actually posts. */
.signin input:disabled{color:var(--wire);background:transparent;cursor:not-allowed}
.err{color:var(--clay);font-size:14px;margin-top:12px}
.fineprint{margin-top:26px;font-size:14px;color:var(--wire)}

/* The enquiry form. Same furniture as signing in, but it is a column of a
   two-up layout rather than a card in the middle of an empty page, so the
   340px that suits a username and a password is a third of the room it has —
   and a paragraph typed into a 340px box is unreadable while you write it. */
.enquiry{max-width:none}
/* "optional" beside a field name, which is the only thing that stops the other
   three reading as optional too. */
.signin label .opt{
  text-transform:none;letter-spacing:.02em;font-size:10px;color:var(--wire);
  opacity:.75;margin-left:6px;
}
/* The honeypot: present in the DOM, absent from the page. Positioned off-screen
   rather than display:none or hidden, both of which a bot worth defending
   against knows to leave alone. aria-hidden and tabindex=-1 in the markup are
   the other half — nothing about it should ever reach a person. */
.hp{position:absolute;left:-9999px;top:auto;width:1px;height:1px;overflow:hidden}

/* ------------------------------------------------------------ tables -- */
/* Two rules make a table readable, and both are set here for every table on
   the site rather than per page.
 *
 * A GUTTER BETWEEN THE COLUMNS. Every cell had zero horizontal padding, which
 * is invisible while a table has room to spare and wrong the moment it does
 * not: at its min-width the columns pack tight and two right-aligned figures
 * print as one, which is how a ₹1,200 charge and invoice 621 came to read as
 * "₹1,200621" on the patient page. The gutter is padding-inline, so it cannot
 * be undone by the vertical padding the tables below set — THOSE ALL USE
 * padding-block FOR EXACTLY THAT REASON, and a `padding: 11px 0` shorthand
 * added to any of them would quietly put the columns back together.
 *
 * The last column gives its gutter back, so a table still starts and ends on
 * the page's own margins rather than floating inside them.
 *
 * A HEADER OVER ITS OWN VALUES. th and td take the same default — first column
 * left, the rest right — and where a cell opts out, its header has to opt out
 * with it. See table.ct th.l / th.r below. */
table{width:100%;border-collapse:collapse}
th,td{padding-inline:0 var(--gut)}
th:last-child,td:last-child{padding-inline-end:0}
th{
  font-family:var(--mono);font-size:10px;letter-spacing:.12em;text-transform:uppercase;
  color:var(--wire);font-weight:400;text-align:right;padding-block:0 10px;
  border-bottom:1px solid var(--rule);
}
th:first-child{text-align:left}
td{padding-block:13px;border-bottom:1px solid var(--rule);text-align:right;font-family:var(--mono);font-size:14px}
td:first-child{text-align:left;font-family:var(--sans);font-size:15px}
td.n{color:var(--wire)}

/* On a phone the gutter costs more than it gives: these tables scroll
   sideways already, and 22px between eleven columns is another 240px of
   scrolling to read one row. */
@media (max-width:560px){
  :root{--gut:14px}
}

/* --------------------------------------------------------- patients -- */
.patients{list-style:none;margin:0;padding:0;border-top:1px solid var(--rule)}
.patients li{border-bottom:1px solid var(--rule)}
.patients a{
  display:flex;justify-content:space-between;align-items:baseline;gap:16px;
  padding:13px 4px;text-decoration:none;
}
.patients a:hover{background:var(--card)}
.patients a.on{background:var(--card);box-shadow:inset 3px 0 0 var(--indigo)}
.patients .who{font-size:15px}
.patients .meta{font-family:var(--mono);font-size:11px;color:var(--wire);letter-spacing:.06em}

/* --------------------------------------------------------- gallery --- */
.gallery{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:14px;margin-top:4px}
.gallery figure{margin:0}
.gallery a{display:block;background:var(--card);border:1px solid var(--rule);border-radius:2px;overflow:hidden}
.gallery img{display:block;width:100%;height:auto;aspect-ratio:4/3;object-fit:cover;background:var(--card)}
.gallery figcaption{
  font-family:var(--mono);font-size:10px;color:var(--wire);
  letter-spacing:.06em;margin-top:6px;word-break:break-all;
}
.empty{color:var(--wire);font-size:15px;padding:20px 0}

/* Lightbox. A <dialog>, so Escape, focus trapping and the backdrop are free. */
dialog.lb{
  border:0;padding:0;background:transparent;max-width:96vw;max-height:96vh;
  overflow:visible;
}
dialog.lb::backdrop{background:rgba(12,16,15,.9)}

.lb-stage{display:flex;align-items:center;gap:6px;position:relative}
dialog.lb img{
  max-width:min(1100px,84vw);max-height:82vh;display:block;
  border-radius:2px;background:var(--card);
}

.lb-nav{
  flex:0 0 auto;background:transparent;border:0;cursor:pointer;
  color:rgba(247,249,248,.65);font-size:44px;line-height:1;
  padding:14px 10px;border-radius:2px;
  font-family:var(--sans);
}
.lb-nav:hover{color:#fff;background:rgba(247,249,248,.08)}
.lb-nav:focus-visible{outline:2px solid #fff;outline-offset:2px}

.lb-bar{
  display:flex;align-items:center;justify-content:space-between;gap:16px;
  padding:12px 4px 0;
}
.lb-bar span{
  font-family:var(--mono);font-size:11px;letter-spacing:.1em;
  color:rgba(247,249,248,.7);
}
.lb-close{
  background:transparent;border:1px solid rgba(247,249,248,.35);
  color:rgba(247,249,248,.85);border-radius:2px;cursor:pointer;
  font-family:var(--mono);font-size:11px;letter-spacing:.1em;padding:7px 14px;
}
.lb-close:hover{background:rgba(247,249,248,.12);color:#fff}

/* -------------------------------------------------- compare photos --- */
/* Two columns at every width, phones included. Stacking them would put the two
   photographs a screenful apart, which is the one thing this page must not do;
   only the spacing gives way. */
.cmp-head{
  display:grid;grid-template-columns:1fr 1fr;gap:14px 20px;
  position:sticky;top:0;z-index:5;
  background:var(--paper);padding:14px 0 12px;border-bottom:1px solid var(--rule);
}
.cmp-opts{
  grid-column:1/-1;display:flex;align-items:center;justify-content:space-between;
  gap:14px;flex-wrap:wrap;
}
.cmp-opts .swap{
  font-family:var(--mono);font-size:11px;letter-spacing:.1em;text-transform:uppercase;
  color:var(--wire);text-decoration:none;border-bottom:1px solid var(--rule);
}
.cmp-opts .swap:hover{color:var(--ink);border-bottom-color:var(--indigo)}

.cmp{margin-top:26px}
.cmp-row{display:grid;grid-template-columns:1fr 1fr;gap:10px 14px;margin-bottom:28px}
.cmp-slot{
  grid-column:1/-1;margin:0;display:flex;align-items:center;gap:12px;
  font-family:var(--mono);font-size:10px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--wire);
}
.cmp-slot:after{content:"";flex:1 1 auto;height:1px;background:var(--rule)}
/* A view that only one of the two visits has is worth noticing, not merely
   worth showing — otherwise the gap reads as a loading failure. */
.cmp-row.odd .cmp-slot{color:var(--clay)}

.cmp-cell{margin:0}
.cmp-cell a{
  display:block;background:var(--card);border:1px solid var(--rule);
  border-radius:2px;overflow:hidden;
}
/* contain, not cover. Cropping two photographs into a common box changes what
   each one shows, which on a page whose whole purpose is comparison is worse
   than a little letterboxing. The fixed ratio is what keeps the two sides the
   same height, and so the rows in step. */
.cmp-cell img{
  display:block;width:100%;aspect-ratio:4/3;object-fit:contain;background:var(--card);
}
.gone{
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:8px;
  aspect-ratio:4/3;border:1px dashed var(--rule);border-radius:2px;color:var(--wire);
}
.gone span{
  font-family:var(--mono);font-size:10px;letter-spacing:.12em;text-transform:uppercase;
}

/* The row heading doubles as the way through to that view's whole run, so it
   has to look like a link without stopping looking like a heading — the rule
   that follows it already does the work of a heading, and an underline is
   enough to say the words themselves go somewhere. */
.cmp-slot a{
  color:inherit;text-decoration:none;border-bottom:1px solid var(--rule);
}
.cmp-slot a:hover{color:var(--ink);border-bottom-color:var(--indigo)}
.cmp-row.odd .cmp-slot a:hover{color:var(--clay);border-bottom-color:var(--clay)}

/* ------------------------------------------------------ progress ----- */
/* Two ways of looking at the same photographs, as tabs. Set like the section
   headings — mono, spaced, small — so the strip reads as part of the page
   rather than as a control bolted onto it. */
.tabs{display:flex;gap:22px;border-bottom:1px solid var(--rule);margin:0 0 4px}
.tabs a{
  font-family:var(--mono);font-size:10.5px;letter-spacing:.13em;
  text-transform:uppercase;text-decoration:none;color:var(--wire);
  padding:0 0 9px;border-bottom:2px solid transparent;margin-bottom:-1px;
}
.tabs a:hover{color:var(--ink)}
.tabs a.on{color:var(--ink);border-bottom-color:var(--indigo)}

.reel-pick{margin:22px 0 16px;max-width:300px}

/* The stage is capped rather than filling the column: a photograph blown up to
   1000px is not easier to read than one at 620, and the strip below it has to
   stay on the same screen as the picture it is scrubbing. */
.reel-stage{margin:0;max-width:620px;position:relative}
.reel-stage a{
  display:block;background:var(--card);border:1px solid var(--rule);
  border-radius:2px;overflow:hidden;
}
/* contain, for the same reason the comparison cells use it: the run is only
   honest if every frame shows the same amount of what was photographed. */
.reel-stage img{
  display:block;width:100%;aspect-ratio:4/3;object-fit:contain;background:var(--card);
}
.reel-stage figcaption{
  position:absolute;left:0;right:0;bottom:0;
  display:flex;justify-content:space-between;align-items:baseline;
  gap:14px;flex-wrap:wrap;padding:26px 13px 10px;pointer-events:none;
  background:linear-gradient(to top,rgba(20,28,26,.72),rgba(20,28,26,0));
  font-family:var(--mono);font-size:11px;letter-spacing:.1em;
  text-transform:uppercase;color:var(--card);
}
.reel-stage figcaption b{font-weight:400;font-size:12px}
.reel-stage figcaption i{font-style:normal;opacity:.74}

/* The strip is the scrubber. Horizontal at every width — wrapping it would
   turn a timeline into a grid, and the whole point is that it reads as one
   run from oldest to newest. */
.reel-strip{
  display:flex;gap:8px;margin-top:10px;max-width:620px;
  overflow-x:auto;padding-bottom:6px;scrollbar-width:thin;
}
.reel-strip a{
  flex:0 0 auto;width:86px;display:block;text-decoration:none;
  background:var(--card);border:1px solid var(--rule);border-radius:2px;
  overflow:hidden;
}
.reel-strip img{
  display:block;width:100%;aspect-ratio:4/3;object-fit:cover;background:var(--card);
}
.reel-strip em{
  display:block;font-style:normal;
  font-family:var(--mono);font-size:9.5px;letter-spacing:.07em;
  text-transform:uppercase;color:var(--wire);
  padding:5px 4px;border-top:1px solid var(--rule);
  white-space:nowrap;text-align:center;
}
.reel-strip a:hover em{color:var(--ink)}
.reel-strip a[aria-current]{border-color:var(--indigo);box-shadow:inset 0 0 0 1px var(--indigo)}
.reel-strip a[aria-current] em{color:var(--ink)}
.reel-strip a:focus-visible{outline:2px solid var(--indigo);outline-offset:2px}

.reel-foot{
  display:flex;align-items:center;justify-content:space-between;
  gap:14px;flex-wrap:wrap;margin-top:14px;max-width:620px;
}
.reel-foot .stamp{margin:0}
.reel-play{
  font-family:var(--mono);font-size:10.5px;letter-spacing:.12em;
  text-transform:uppercase;color:var(--wire);cursor:pointer;
  background:transparent;border:1px solid var(--rule);border-radius:2px;
  padding:7px 13px;
}
.reel-play:hover{background:var(--indigo);color:#fff;border-color:var(--indigo)}
.reel-play:focus-visible{outline:2px solid var(--indigo);outline-offset:2px}

@media (max-width:860px){
  /* The arch leads on a narrow screen — it is the practice's name, and the
     headline reads better under it than beside a sign squeezed to a third of
     the width. Centred here rather than ranged right, because at this width
     the column is the page and the arch is the top of it.

     The top radius is left at its full value: a browser scales radii that
     overrun their box proportionally, so the semicircle survives the narrower
     arch without a second number to keep in step with the width. */
  .hero-in{grid-template-columns:1fr;gap:36px;padding-top:44px;padding-bottom:52px}
  .arch{justify-self:center;max-width:330px;order:-1;padding:70px 28px 36px}
  .hero:after{right:auto;left:50%;top:22%;transform:translate(-50%,-50%)}
  .hero h1{max-width:none}
  .closer-in{padding-top:40px;padding-bottom:44px}
  /* The tooth goes above the name rather than beside it: the specialism is a
     long line of tracked capitals, and at this width it is what decides how
     wide the lockup can be. */
  .closer-sign{flex-direction:column;text-align:center;gap:14px;padding-bottom:40px}
}

@media (max-width:760px){
  .cols{grid-template-columns:1fr}
  /* One card to a row is as wide as the column, and an arch that wide is a
     rounded rectangle with a lot of empty air under its curve. Below this
     width the cards go back to being cards. */
  .home .cols section{border-radius:3px;padding:26px 24px 28px;text-align:left}
  .home .cols .num{margin-bottom:14px}
  .home .cols p{max-width:none;margin:0}
  .masthead{gap:12px;position:relative}
  .masthead nav{gap:16px;flex-wrap:wrap}
  /* The menu hangs off the masthead rather than off the portrait here: the
     nav wraps on a narrow screen, so the portrait ends up wherever there is
     room and a panel anchored to it drops off the side of the page. */
  .acct{position:static}
  .acct-menu{right:24px;top:calc(100% + 6px)}
  .mapcard iframe{height:220px}
  /* On a phone, arrows beside the photo would squeeze it and be too small to
     tap. Overlay them on the edges instead, at a proper touch-target size.
     Swipe works too. */
  dialog.lb img{max-width:94vw}
  .lb-nav{
    position:absolute;top:50%;transform:translateY(-50%);
    font-size:34px;padding:0 10px;min-width:46px;min-height:64px;
    background:rgba(12,16,15,.45);color:#fff;
  }
  .lb-prev{left:0}
  .lb-next{right:0}
  .split{grid-template-columns:1fr;gap:32px}
  th.hide,td.hide{display:none}
  /* The two columns stay side by side here — see the note above. */
  .cmp-head{gap:10px;padding:10px 0}
  .cmp-row{gap:8px;margin-bottom:20px}
  .gone{gap:4px}
  .gone svg{width:20px;height:20px}
}

/* -------------------------------------------------- dashboard only --- */
/* The line under a page title. Body font rather than monospace: it is a
   sentence about the page, not a readout, and under a serif title a row of
   monospace reads as console output. */
.sub{font-size:16.5px;color:var(--wire);margin:0 0 12px}
.sub b{color:var(--ink);font-weight:500;font-family:var(--mono);font-size:15.5px}
.stamp{font-family:var(--mono);font-size:11px;letter-spacing:.1em;
  text-transform:uppercase;color:var(--wire);margin:0 0 30px}

/* Title, summary line and sync stamp as one block, ruled off from the figures
   below it: the page says what it is, then reports. */
.pagehead{border-bottom:1px solid var(--rule);padding-bottom:26px}
.pagehead h1{margin-bottom:12px}
.pagehead .stamp{margin-bottom:0}

/* A panel is the page's one surface: a card the colour of paper's lighter
   cousin, hairline-ruled. Figures sit in them, and so does the chart. */
.panel{
  background:var(--card);border:1px solid var(--rule);border-radius:3px;
  padding:24px 26px;
}

.figures{display:grid;grid-template-columns:repeat(4,1fr);gap:14px;margin:30px 0 0}
.figures > div{
  background:var(--card);border:1px solid var(--rule);border-radius:3px;
  padding:20px 20px 22px;
}
.figures dt{
  font-family:var(--mono);font-size:10px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--wire);
}
/* The headline figures are set in the serif, at a size no table cell would
   use. They are the page's statement, not its data — the tables below stay
   monospaced, where a column of digits has to line up. */
.figures dd{
  margin:12px 0 0;font-family:var(--serif);font-size:44px;font-weight:400;
  line-height:1;letter-spacing:-.02em;
}
.figures .note{
  margin:9px 0 0;font-size:12.5px;line-height:1.4;color:var(--wire);
}
.figures .lead{background:var(--ink);border-color:var(--ink);color:var(--paper)}
.figures .lead dt{color:rgba(237,240,239,.6)}
.figures .lead .note{color:rgba(237,240,239,.6)}

.strip{display:flex;height:46px;border-radius:3px;overflow:hidden;gap:2px;margin-top:4px}
.strip .seg{position:relative;min-width:3px;background:var(--indigo);
  display:flex;align-items:center;justify-content:center}
.strip .seg span{font-family:var(--mono);font-size:11px;color:#fff;
  letter-spacing:.04em;white-space:nowrap;padding:0 8px;opacity:.95}
.strip-key{display:flex;flex-wrap:wrap;gap:4px 20px;margin:12px 0 0;
  font-family:var(--mono);font-size:12px;color:var(--wire)}
.strip-key i{display:inline-block;width:8px;height:8px;border-radius:1px;
  margin-right:7px;vertical-align:middle;background:var(--indigo)}
.strip-key b{color:var(--ink);font-weight:500}

/* The counts get a column each of the same width, so they line up under their
   headings instead of bunching at whatever width the longest clinic name
   leaves over. */
table.clinics{margin-top:30px;table-layout:fixed}
table.clinics th:first-child,table.clinics td:first-child{width:auto}
table.clinics th:not(:first-child),table.clinics td:not(:first-child){width:120px}
table.clinics td:first-child{font-size:15.5px}
table.clinics td{padding-block:15px}

/* New registrations by month. Each bar carries its own height and shade as
   custom properties, so hover can take the shade to full without having to
   out-shout an inline style. The top padding is where a tooltip on the tallest
   bar goes; without it the figure would draw over the heading. */
.months{margin-top:4px;padding-top:34px}
.months-plot{
  display:flex;align-items:flex-end;gap:2px;height:130px;
  border-bottom:1px solid var(--rule);
}
.mbar{position:relative;flex:1 1 0;height:100%;display:flex;align-items:flex-end}
.mbar i{display:block;width:100%;height:var(--h);background:var(--indigo);opacity:var(--o)}
.mbar:hover i,.mbar:focus-visible i{opacity:1}
.mbar:focus{outline:none}
.mbar:focus-visible{outline:1px solid var(--indigo);outline-offset:2px}

/* Sits just above the bar it belongs to, not above the plot: a figure floating
   at the top of the chart would have to be traced back down to the month it
   describes. The first and last are anchored to their own edge so a tooltip
   cannot push the page sideways on a phone. */
.mbar-tip{
  position:absolute;left:50%;bottom:calc(var(--h) + 6px);transform:translateX(-50%);
  font-family:var(--mono);font-size:11px;font-weight:400;letter-spacing:.02em;
  white-space:nowrap;background:var(--ink);color:var(--paper);
  padding:4px 8px;border-radius:2px;
  opacity:0;visibility:hidden;transition:opacity .12s ease;pointer-events:none;
}
.mbar.at-start .mbar-tip,.fcol.at-start .mbar-tip{left:0;transform:none}
.mbar.at-end .mbar-tip,.fcol.at-end .mbar-tip{left:auto;right:0;transform:none}
.mbar:hover .mbar-tip,.mbar:focus-visible .mbar-tip,
.fcol:hover .mbar-tip,.fcol:focus-visible .mbar-tip{opacity:1;visibility:visible}

.months-axis{
  display:flex;justify-content:space-between;margin:9px 0 0;
  font-family:var(--mono);font-size:11px;letter-spacing:.1em;
  text-transform:uppercase;color:var(--wire);
}

@media (max-width:900px){
  .figures{grid-template-columns:repeat(2,1fr)}
}
@media (max-width:760px){
  /* Two of the count columns are hidden at this width; the rest give back
     enough room that a clinic name stops wrapping to four lines. */
  table.clinics th:not(:first-child),table.clinics td:not(:first-child){width:76px}
}
@media (max-width:560px){
  .strip .seg span{display:none}
  .figures dd{font-size:36px}
}

/* -------------------------------------------------- contracts page --- */
.wrap.wide{max-width:1160px}

.tot{display:grid;grid-template-columns:repeat(6,1fr);gap:1px;background:var(--rule);
  border-top:1px solid var(--rule);border-bottom:1px solid var(--rule);margin:6px 0 0}
.tot > div{background:var(--paper);padding:15px 14px}
.tot dt{font-family:var(--mono);font-size:9.5px;letter-spacing:.12em;
  text-transform:uppercase;color:var(--wire)}
.tot dd{margin:6px 0 0;font-family:var(--mono);font-size:19px;font-weight:500;
  letter-spacing:-.02em}
.tot .lead dd{color:var(--indigo)}
.tot .out dd{color:var(--clay)}

/* The rupee sits at half weight so columns align on the digits. */
.r{opacity:.5;margin-right:1px}
.nil{color:var(--wire);opacity:.5}

.scroller{overflow-x:auto}
table.ct{min-width:1000px}
table.ct td{padding-block:11px;font-size:13px}
table.ct td.who{font-family:var(--sans);font-size:14.5px;text-align:left}
table.ct td.d,table.ct td.ty{text-align:left;font-size:11.5px;color:var(--wire)}
table.ct th{white-space:nowrap;font-size:9.5px}
/* These are wide tables, and several of them are wider than the screen. The
   row under the pointer is lit so the eye can carry a name at the left edge
   across to a figure at the right one without losing the line. */
table.ct tbody tr:hover > td{background:var(--card)}

/* A date is three words to the layout and one to a reader, so it does not
   break: a squeezed column setting "3 Jan 2024" as two lines is the table
   buying its width back out of legibility, and it staggers every figure in
   the row beside it.
 *
 * Named column by column rather than as `td.d`, because .d also carries
 * clinic names, item categories and supplier names — "Ortho World
 * Distributors" held on one line would push the table wider than the screen
 * on its own, which is the fault this rule exists to avoid. */
td.dt{white-space:nowrap}
table.ct.cn td.d,table.ct.inv td.d,table.ct.mv td.d,table.ct.pvs td.d{white-space:nowrap}
/* Status checkboxes + name search */
.checks{display:flex;flex-wrap:wrap;gap:8px}
.chk{display:inline-flex;align-items:center;gap:7px;cursor:pointer;
  border:1px solid var(--rule);border-radius:2px;padding:9px 12px;
  background:var(--card);font-size:13.5px;line-height:1}
.chk:hover{border-color:var(--wire)}
.chk input{accent-color:var(--indigo);margin:0;width:14px;height:14px}
.chk input:checked + span{color:var(--ink)}
.chk span{color:var(--wire)}

input[type=search]{
  width:100%;font-family:var(--sans);font-size:15px;color:var(--ink);
  background:var(--card);border:1px solid var(--rule);border-radius:2px;
  padding:11px 12px;appearance:none;
}
input[type=search]:focus{outline:2px solid var(--indigo);outline-offset:-1px}

/* Headers align with their cells. The shared table rule right-aligns every
   th except the first, which left the Patient and Type headers hanging over
   left-aligned text. */
table.ct th.l{text-align:left}
table.ct th.r{text-align:right}
table.ct th a{text-decoration:none;color:inherit}
table.ct th a:hover{color:var(--ink)}
table.ct th.s a:after{content:" ↕";opacity:.3}
table.ct th.on a:after{content:" ↑";opacity:1;color:var(--indigo)}
table.ct th.on.desc a:after{content:" ↓"}

/* The clinic's address, under its name in the invoice summary. A second line
   inside the value rather than a figure of its own: it qualifies the clinic
   rather than standing beside it. */
.tot dd .sub,
.tot dd .nil{display:block;margin:4px 0 0;font-size:12.5px;line-height:1.45}

/* Invoices. Narrower than the contracts table because it carries five columns
   rather than eleven, and one of them is a sentence: "Treatment done" is the
   status prose, so it takes the width the others do not need and wraps rather
   than forcing the table wider than the screen. */
table.ct.inv{min-width:760px}
table.ct.inv td.did{
  text-align:left;font-size:12.5px;line-height:1.5;color:var(--ink);
}
table.ct.inv td.ty{white-space:nowrap}
/* The two summary rows are the invoice's own, not a running total of what is
   on screen, so they are ruled off from the lines above them. */
table.ct.inv tfoot td{border-top:1px solid var(--rule);padding-block:13px 0}
table.ct.inv tfoot .sum td{
  font-family:var(--mono);font-size:11px;letter-spacing:.12em;text-transform:uppercase;
  color:var(--wire);text-align:right;
}
table.ct.inv tfoot .sum td:last-child{color:var(--indigo);letter-spacing:0;font-size:14px}
table.ct.inv tfoot .words td{
  border-top:0;padding-top:6px;text-align:right;font-size:12.5px;color:var(--wire);
}

/* Export progress. The bar is indeterminate on purpose: the export is a single
   request, so there is no percentage to be had, and a fake one that sat at 90%
   would be worse than an honest stripe that keeps moving. It runs only while
   .working is set, so it stops the moment there is an answer. */
.expo{margin-top:16px;max-width:560px}
.expo-bar{height:3px;background:var(--rule);border-radius:2px;overflow:hidden;opacity:0}
.expo.working .expo-bar{opacity:1}
.expo-bar i{
  display:block;height:3px;width:40%;border-radius:2px;background:var(--indigo);
  transform:translateX(-100%);
}
.expo.working .expo-bar i{animation:expo-slide 1.15s ease-in-out infinite}
@keyframes expo-slide{
  0%   {transform:translateX(-100%)}
  100% {transform:translateX(250%)}
}
.expo-msg{
  margin:9px 0 0;font-family:var(--mono);font-size:11.5px;letter-spacing:.06em;
  color:var(--wire);line-height:1.6;
}
.expo-msg a{color:var(--indigo)}
.expo.bad .expo-msg{color:var(--clay)}
/* A document that was made, with something imperfect about it. */
.expo-warn{display:block;margin-top:5px;color:var(--clay);font-style:italic}

/* Someone who has asked not to see motion still needs to know it is working,
   so the bar holds still and the seconds in the message do the telling. */
@media (prefers-reduced-motion: reduce){
  .expo.working .expo-bar i{animation:none;transform:none;width:100%;opacity:.45}
  /* The card still answers the pointer — it just stops moving to do it. */
  .home .cols section{transition:none}
  .home .cols section:hover{transform:none}
}

/* The export is an action, not a destination, so it is a button — styled to sit
   level with the links beside it in the same row. */
.tools button{
  font-family:var(--mono);font-size:12px;letter-spacing:.08em;cursor:pointer;
  border:1px solid var(--indigo);color:var(--indigo);background:transparent;
  padding:11px 19px;border-radius:2px;
}
.tools button:hover{background:var(--indigo);color:#fff}
.tools button.primary{background:var(--indigo);color:#fff}
.tools button.primary:hover{background:var(--ink);border-color:var(--ink)}
.tools button[disabled]{opacity:.5;cursor:progress}
.tools button[disabled]:hover{background:var(--indigo);border-color:var(--indigo)}

.ful{white-space:nowrap}
.fbar{display:inline-block;width:46px;height:3px;background:var(--rule);
  border-radius:2px;vertical-align:middle;margin-right:7px;overflow:hidden}
.fbar i{display:block;height:3px;background:var(--indigo)}
.ful b{font-weight:400;color:var(--wire);font-size:11.5px}

.pill{font-family:var(--mono);font-size:9.5px;letter-spacing:.07em;padding:3px 7px;
  border-radius:2px;border:1px solid var(--rule);color:var(--wire);white-space:nowrap}
.pill.prog{border-color:var(--indigo);color:var(--indigo)}
.pill.disc{border-color:rgba(181,101,29,.5);color:var(--clay)}
td.owed,td.bal{color:var(--clay)}
td.cred{color:var(--indigo)}

@media (max-width:900px){
  .tot{grid-template-columns:repeat(2,1fr)}
}

/* ---------------------------------------------------- schedule page --- */
.tot.sched{grid-template-columns:repeat(4,1fr)}
.tot dd.sm{font-size:16px}

/* The clinic heading and the way to get to it, on one line. The link keeps the
   .tools button styling used everywhere else an action sits next to prose;
   baseline alignment is what stops it floating above a two-line heading on a
   narrow screen. */
.sched-head{display:flex;align-items:baseline;justify-content:space-between;
  gap:18px;flex-wrap:wrap}
.sched-head h2{margin-bottom:0}
.sched-head .tools{margin:0}

/* Every value centred, headers included — the columns are short and mixed,
   so left/right alignment made it hard to track a row across. */
table.sc{min-width:900px}
table.sc th,table.sc td{text-align:center}
table.sc td{padding-block:11px;font-size:13px;font-family:var(--mono)}
table.sc td.who{font-family:var(--sans);font-size:14.5px}
table.sc th{font-size:9.5px;white-space:nowrap;padding-bottom:10px}
table.sc td.late{color:var(--clay)}

.wa{border:1px solid var(--rule);border-radius:2px;background:var(--card);
  padding:20px 22px;margin-top:34px;display:grid;
  grid-template-columns:1fr auto;gap:26px;align-items:start}
.wa h3{margin:0 0 10px;font-family:var(--mono);font-size:10px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--wire);font-weight:400}
.wa pre{margin:0;font-family:var(--sans);font-size:13.5px;line-height:1.6;
  color:var(--ink);white-space:pre-wrap;max-height:240px;overflow:auto}
.wa .go{display:inline-block;background:#1EA855;color:#fff;text-decoration:none;
  border:0;cursor:pointer;font-family:var(--mono);font-size:12px;letter-spacing:.08em;
  padding:13px 20px;border-radius:2px;white-space:nowrap}
.wa .go:hover{background:#17853F}
.wa .num{font-family:var(--mono);font-size:11px;color:var(--wire);
  margin:9px 0 0;text-align:center}
@media (max-width:820px){
  .tot.sched{grid-template-columns:repeat(2,1fr)}
  .wa{grid-template-columns:1fr}
}

/* Three tiles rather than the contracts page's six — the caseload page's login
   figures. Was shared with a birthdays page, which is gone. */
.tot.three{grid-template-columns:repeat(3,1fr)}

@media (max-width:560px){
  .tot.three{grid-template-columns:repeat(2,1fr)}
}

/* ----------------------------------------------------- patient page --- */
/* Portrait, name and where they are treated, in one lockup — the same idea as
   .idcard on the profile page, but the heading is the patient's name rather
   than a paragraph about them, so it takes h1 and the meta sits under it. */
.ptop{display:flex;align-items:center;gap:26px;margin:0 0 30px}
.ptop h1{margin:0 0 8px}
.ptop .sub{margin:0 0 14px}
.ptop .tools{margin:0}

/* The duplicate-username warning. Clay rather than a pill, because it is not a
   status on the record — it is a statement that the record may be two people
   and nothing under it can be trusted until the sheet is fixed. */
.warn{border:1px solid rgba(181,101,29,.5);border-left:3px solid var(--clay);
  background:var(--card);border-radius:2px;padding:15px 18px;margin:0 0 26px;
  font-size:14.5px;line-height:1.6;color:var(--ink)}
.warn b{font-weight:500}

/* Four tables, all of them .ct, differing only in how much they have to fit.
   The visits table is the widest because one of its columns is a sentence and
   four more are money; the others are narrower and stop forcing a scroller on
   a laptop.
 *
 * .pvs, NOT .pv. The visits table used to carry the payments page's pivot
 * class, which is a different table with a different shape — it inherited the
 * pivot's 720px (seven columns in the width the pivot uses for five, which is
 * what pushed the charge and the invoice number into each other) and, worse,
 * lent it the `th:nth-child(3)` rule below, which ranged the pivot's
 * Reimbursable heading left over a column of right-aligned money. Two tables,
 * two classes. */
table.ct.pt{min-width:860px}
table.ct.pm{min-width:880px}
table.ct.pe{min-width:900px}
table.ct.pvs{min-width:920px}
/* The status sentence. Ranged left and allowed to wrap — it is prose, and the
   mono digits the rest of the row is set in would make it unreadable. */
table.ct.pvs td.did{text-align:left;font-family:var(--sans);font-size:13px;
  line-height:1.5;color:var(--wire);max-width:34ch;white-space:normal}

/* Where a material went. One row of the materials table is an item, and the
   arches and quadrants it was used in are badges across this column rather
   than a row each — a molar tube case is four rows of "1" otherwise, and the
   answer to "how many tubes" is then something the reader has to add up.
   Allowed to wrap, because four quadrants at full width will not fit beside
   the columns either side of them on a laptop. */
table.ct.pm td.site{text-align:left;white-space:normal;line-height:2.1}
.arch{display:inline-block;margin:0 4px 0 0}
/* The count rides inside the badge, and only when there is more than one —
   "Upper" already says it happened once. */
.arch b{font-weight:400;color:var(--ink);margin-left:5px}

table.ct td.who a{text-decoration:none;border-bottom:1px solid transparent}
table.ct td.who a:hover{border-bottom-color:var(--indigo)}

/* One date's photographs, headed by the date. Tighter than an h2 because the
   run of them is a contact sheet rather than a run of sections. */
h3.pdate{font-family:var(--mono);font-size:10px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--wire);font-weight:400;
  margin:26px 0 10px;padding-bottom:8px;border-bottom:1px solid var(--rule)}

@media (max-width:560px){
  .ptop{flex-direction:column;align-items:flex-start;gap:18px}
}

/* ------------------------------------------------------- spend page --- */
/* Wider than the contracts page's 46px bar, which sits in a row of ten money
   columns and only has to hint. Here the bar IS the comparison between rows,
   so it gets room to be read. */
.fbar.wide{width:120px}
/* Four and six columns, both narrower than a contract row — these tables are
   a label and a figure, not a ledger. */
table.ct.sp{min-width:560px}
table.ct.spp{min-width:820px}
/* The Share column is a bar, and its header says so by being ranged left.
   Right-aligned — which is what every other cell in these tables is — the
   bars grew leftwards from a common right edge and could not be compared
   against each other at all, which is the one thing a bar is for. */
table.ct.sp td.ful,table.ct.spp td.ful{text-align:left}

@media (max-width:560px){
  .fbar.wide{width:70px}
}

/* ------------------------------------------------- wire timeline --- */
.railhead{font-family:var(--mono);font-size:10px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--wire);font-weight:400;margin:26px 0 8px}

/* One row per wire, every row of BOTH ARCHES on one time axis: the bar's
   distance from the left edge is when that wire went in, and its length is how
   long it stayed. The run reads as a staircase down the page, which is the
   sequence, and the widths are the pacing.
 *
 * One axis is what lets the two arches be read against each other. Each was
 * once scaled to its own run, which made the two charts the same width and
 * meant nothing lined up between them — 40% along the upper and 40% along the
 * lower were different months. Now a vertical line through the page is a
 * moment in time, and the ruled lines are there so the eye can follow one
 * across the gap between the lanes.
 *
 * WHY NOT THE SINGLE RAIL THIS REPLACES. That was one proportional strip per
 * arch with the wires listed underneath, and it was accurate and unreadable:
 * the segments carried no labels at all, the list under them was a grid that
 * wrapped to whatever fitted, and its cells lined up with nothing above them.
 * Reading it meant counting blocks from the left, then counting cards in
 * reading order, and trusting that the two counts met. Labelling the segments
 * in place would not have fixed it either — a wire in for eleven days is a
 * three-pixel segment on a case that ran two years, and no label goes in
 * there. A bar that cannot hold its own label needs a row that can. */
.wchart{--wcols:minmax(0,15em) minmax(90px,1fr) minmax(0,13em)}
.wscale,.wchart ol.wseq li{
  display:grid;grid-template-columns:var(--wcols);gap:8px 20px;align-items:center;
}
.wscale{padding:0 2px 7px}
/* The axis labelled once, at the top, rather than a date on every line. */
.wspan{font-family:var(--mono);font-size:10px;letter-spacing:.1em;
  text-transform:uppercase;color:var(--wire);font-weight:400}
.wscale .wtrack{position:relative;height:14px;background-image:none}
.wscale i{
  position:absolute;top:0;left:0;transform:translateX(-50%);
  font-family:var(--mono);font-size:10px;letter-spacing:.08em;color:var(--wire);
  font-style:normal;white-space:nowrap;
}

.wchart ol.wseq{list-style:none;margin:0;padding:0;
  border-top:1px solid var(--rule);counter-reset:wire}
.wchart ol.wseq li{
  padding:11px 2px;border-bottom:1px solid var(--rule);counter-increment:wire;
}
.wchart ol.wseq li:hover{background:var(--card)}
/* The lane heading. Ruled off above so the two arches read as two blocks of
   one chart rather than as two charts. */
.railhead.wlane{margin:22px 0 7px}

.wname{font-family:var(--sans);font-size:14.5px;font-weight:500;color:var(--ink)}
/* Scoped to a row in a lane. The scale row above the lanes takes the same
   first column and is not a wire, so it must not be numbered. */
.wchart ol.wseq li .wname::before{content:counter(wire) ". ";font-family:var(--mono);
  font-size:11px;font-weight:400;color:var(--wire)}

/* The full height of the row, so the ruled lines run the height of the row and
   read as continuous verticals down the chart. The custom properties are set
   on .wchart by wire_chart() and inherited here: every track is the same
   width, so identical backgrounds line up without anything measuring them. */
.wtrack{
  position:relative;align-self:stretch;display:flex;align-items:center;
  background-image:var(--tick-img,none);
  background-position:var(--tick-pos,0 0);
  background-size:var(--tick-size,auto);
  background-repeat:no-repeat;
}
/* Same hairline-and-fill idea as the .fbar in the money tables, which is the
   other place on the site where a bar sits inside a track. */
.wbar{position:relative;display:block;width:100%;height:6px;border-radius:3px;
  background:var(--rule)}
.wbar i{
  position:absolute;top:0;bottom:0;left:var(--from,0%);width:var(--len,0%);
  min-width:3px;border-radius:3px;background:var(--indigo);opacity:.78;
}
/* The wire in the mouth now — the row somebody opening this page is usually
   looking for, so it is the one drawn at full strength, and its length reads
   "in now" rather than as a finished span. */
.wchart ol.wseq li.now .wbar i{opacity:1}
.wchart ol.wseq li.now .wlen{color:var(--indigo)}

.wmeta{text-align:right}
.wdate{display:block;font-family:var(--mono);font-size:11px;color:var(--wire);
  white-space:nowrap}
.wlen{display:block;font-size:12.5px;color:var(--wire);margin-top:2px}

/* Narrow: the track takes a line of its own under the row rather than being
   squeezed between a wire name and a date range, neither of which can give
   up any more width. The ruled lines still line up, because every track is
   still the full width of the same column. */
@media (max-width:620px){
  .wchart{--wcols:1fr auto}
  .wchart ol.wseq li{gap:9px 14px}
  .wname{grid-column:1;grid-row:1}
  .wmeta{grid-column:2;grid-row:1}
  .wchart ol.wseq li .wtrack{grid-column:1/-1;grid-row:2}
  .wscale .wspan{grid-column:1/-1;grid-row:1}
  .wscale .wtrack{grid-column:1/-1;grid-row:2;margin-top:4px}
  .wscale .wmeta{display:none}
}

/* ---------------------------------------------------- outcomes page --- */
/* Six columns, four of them short — a duration table is narrower than a
   ledger, and forcing the contracts width on it would put a scroller under a
   table that fits. */
table.ct.oc{min-width:720px}
/* The public cut of the same table: four columns instead of six, and it sits on
   a marketing page rather than in a tool, so it fits a phone without a
   scroller. */
table.ct.oc.pub{min-width:480px;margin-top:2px}
/* The range reads as a pair rather than a figure, so it drops the emphasis the
   monospace columns beside it carry — but it is still a pair of numbers in a
   run of numeric columns, so it keeps their alignment. The .ty default is
   ranged left, which left "12–34" sitting under the left edge of a Range
   heading ranged right. */
table.ct.oc td.ty{font-family:var(--mono);font-size:12px;text-align:right}

/* ---------------------------------------------------- profile page --- */
/* Portrait beside the introduction, so the page opens with the patient
   rather than with a paragraph about them. */
.idcard{display:flex;align-items:center;gap:26px;margin:0 0 34px}
.idcard .lede{margin:0}
.portrait{margin:0;flex:0 0 auto;text-align:center}
.portrait figcaption{
  font-family:var(--mono);font-size:9.5px;letter-spacing:.12em;
  text-transform:uppercase;color:var(--wire);margin-top:9px;
}
@media (max-width:560px){
  .idcard{flex-direction:column;align-items:flex-start;gap:18px}
}

/* ----------------------------------------------- appointments page --- */
/* The summary reuses the contracts .tot grid, but half its tiles hold words
   rather than figures. The numeric styling is monospace and large, which a
   clinic name wears badly, so text tiles opt back into the body font. */
.tot dd.txt{font-family:var(--sans);font-size:14.5px;font-weight:400;
  letter-spacing:0;line-height:1.35}
.tot dd.txt .pill{display:inline-block}

/* One expandable row per visit. The whole summary is the hit target, so the
   marker is decoration — no separate button to aim at on a phone. */
.visits{border-top:1px solid var(--rule);margin-top:4px}
.visit{border-bottom:1px solid var(--rule)}
.visit > summary{
  display:flex;align-items:baseline;justify-content:space-between;gap:16px;
  padding:16px 4px 16px 26px;cursor:pointer;position:relative;
  list-style:none;   /* Firefox's default triangle */
}
.visit > summary::-webkit-details-marker{display:none}
.visit > summary:hover{background:var(--card)}
.visit > summary:focus-visible{outline:2px solid var(--indigo);outline-offset:-2px}
/* Chevron, rotating a quarter turn when the row opens. */
.visit > summary:before{
  content:"";position:absolute;left:6px;top:50%;width:6px;height:6px;
  border-right:1.5px solid var(--wire);border-bottom:1.5px solid var(--wire);
  transform:translateY(-70%) rotate(-45deg);transition:transform .15s ease;
}
.visit[open] > summary:before{transform:translateY(-50%) rotate(45deg)}
.visit[open] > summary{background:var(--card)}
.visit .vt{font-size:15.5px;font-weight:500}
.visit[open] .vt{color:var(--indigo)}
.visit .vmeta{
  font-family:var(--mono);font-size:11px;letter-spacing:.06em;color:var(--wire);
  text-align:right;
}
.visit .vbody{padding:6px 4px 30px}
.visit .vbody h3{
  font-family:var(--mono);font-size:11px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--wire);font-weight:400;margin:30px 0 10px;
}
.visit .vbody .empty{padding:10px 0}

/* What was done at a visit: one clause per line, as the sheet composes them.
   Numbered rather than bulleted would imply an order they were done in, which
   the status text does not record. */
.didlist{list-style:none;margin:0;padding:0;border-top:1px solid var(--rule)}
.didlist li{padding:13px 2px 13px 18px;border-bottom:1px solid var(--rule);
  font-size:15px;line-height:1.45;position:relative}
.didlist li:before{content:"";position:absolute;left:2px;top:21px;
  width:5px;height:5px;border-radius:1px;background:var(--indigo);opacity:.55}

@media (max-width:900px){
  .tot dd.txt{font-size:14px}
}
@media (max-width:560px){
  /* Date and photo count under the title rather than squeezed beside it. */
  .visit > summary{flex-direction:column;align-items:flex-start;gap:5px}
  .visit .vmeta{text-align:left}
}

/* -------------------------------------------------- payments page ---- */
/* A line of explanation under a section heading rather than under the page
   title, so it is set smaller than the page's own lede and does not compete
   with it. */
.lede.sm{font-size:15.5px;margin:-6px 0 20px;max-width:62ch}

/* The pivot. Three levels of row in one table, told apart by indent, weight
   and colour — the same three signals a spreadsheet's outline uses, because
   this is that table and it should be recognisable as it.

   The indent is a custom property set on the row and read by its label,
   rather than a padding rule per level. Levels are distinguished by a class on
   the <tr>, which loses every specificity contest against `table.ct.pv td`;
   an inherited property does not have that argument in the first place. */
table.ct.pv{min-width:720px}
table.ct.pv td{padding-block:0;font-size:13px}
table.ct.pv td.lbl{text-align:left;font-family:var(--sans);font-size:14px}
table.ct.pv tr[hidden]{display:none}
table.ct.pv td:not(.lbl){padding-block:11px}

/* Padding lives on the cell contents rather than the cell, so the whole width
   of a row's first column is the hit target for opening it. */
table.ct.pv td.lbl > span{display:block;padding:11px 0 11px var(--in,0px)}
table.ct.pv .pv-tog{
  display:block;width:100%;text-align:left;background:none;border:0;
  cursor:pointer;font-family:inherit;font-size:inherit;color:inherit;
  position:relative;padding:11px 0 11px calc(var(--in,0px) + 22px);
}
/* Chevron, a quarter turn when the row opens — the same one the appointments
   page draws on a visit. */
table.ct.pv .pv-tog:before{
  content:"";position:absolute;left:var(--in,0px);top:50%;width:5px;height:5px;
  border-right:1.5px solid var(--wire);border-bottom:1.5px solid var(--wire);
  transform:translateY(-70%) rotate(-45deg);transition:transform .15s ease;
}
table.ct.pv .pv-tog[aria-expanded=true]:before{transform:translateY(-50%) rotate(45deg)}
table.ct.pv .pv-tog:focus-visible{outline:2px solid var(--indigo);outline-offset:-2px}

table.ct.pv .pv-y > td{border-top:1px solid var(--rule)}
table.ct.pv .pv-y td.lbl{font-size:16px;font-weight:500}
table.ct.pv .pv-y:hover > td{background:var(--card)}

table.ct.pv .pv-m{--in:22px}
table.ct.pv .pv-m:hover > td{background:var(--card)}

/* Leaf rows. No chevron and nothing to press, so they are indented past where
   a chevron would be rather than stopping short of one. */
table.ct.pv .pv-c{--in:66px}
table.ct.pv .pv-c td{color:var(--wire);font-size:12.5px}
table.ct.pv .pv-c td.lbl{font-size:13.5px}

table.ct.pv tfoot td{
  border-top:1px solid var(--ink);border-bottom:0;padding-block:13px 0;
  font-weight:500;
}
table.ct.pv tfoot td.lbl{font-family:var(--mono);font-size:10px;
  letter-spacing:.12em;text-transform:uppercase;color:var(--wire)}

/* The clinic the picker is on, highlighted where it sits in the full list. */
tr.picked td{background:var(--card);box-shadow:inset 3px 0 0 var(--indigo)}

/* Billed against received. Two bars a month, one scale, drawn the same way as
   the caseload's chart so the two pages read as one set. The extra headroom is
   for the tooltip, which is three lines here rather than one. */
.flow{margin-top:4px;padding-top:64px}
.fcol .mbar-tip{
  white-space:normal;width:max-content;max-width:160px;
  line-height:1.5;text-align:left;padding:6px 9px;
}
/* Direct children only. inr() wraps the rupee sign in a span of its own to
   half-weight it, and a blanket rule here put the ₹ on a line above its
   digits. */
.fcol .mbar-tip > span{display:block}
.flow-plot{
  display:flex;align-items:flex-end;gap:3px;height:150px;
  border-bottom:1px solid var(--rule);
}
.fcol{
  position:relative;flex:1 1 0;height:100%;
  display:flex;align-items:flex-end;justify-content:center;gap:1px;
}
.fcol i{display:block;width:46%;height:var(--h);min-height:1px}
.fcol i.bi{background:var(--wire);opacity:.42}
.fcol i.re{background:var(--indigo);opacity:.8}
.fcol:hover i.bi,.fcol:focus-visible i.bi{opacity:.65}
.fcol:hover i.re,.fcol:focus-visible i.re{opacity:1}
.fcol:focus{outline:none}
.fcol:focus-visible{outline:1px solid var(--indigo);outline-offset:2px}

.ckey{display:flex;flex-wrap:wrap;gap:4px 22px;margin:14px 0 0;
  font-family:var(--mono);font-size:11.5px;color:var(--wire)}
.ckey i{display:inline-block;width:8px;height:8px;border-radius:1px;
  margin-right:7px;vertical-align:middle}
.ckey i.bi{background:var(--wire);opacity:.42}
.ckey i.re{background:var(--indigo);opacity:.8}

/* A caseload count is three digits and a payment total is ten, so these tiles
   run out of room a good deal earlier than the ones on the dashboard. One
   column rather than a figure clipped or a page that scrolls sideways. */
@media (max-width:620px){
  .figures.money{grid-template-columns:1fr}
}
@media (max-width:560px){
  table.ct.pv .pv-c{--in:44px}
  .flow-plot{height:120px}
}

/* ---------------------------------------------------------- materials -- */

/* The inventory carries six short columns and one long name, so it does not
   need the width the contracts table does — but it does need the name column
   to have room, because "0.017x0.025 NiTi with curve of Spee Lower" is the
   longest string on the site. */
table.ct.stk{min-width:820px}
table.ct.stk.narrow{min-width:480px}
table.ct.stk td.who a{text-decoration:none;border-bottom:1px solid transparent}
table.ct.stk td.who a:hover{border-bottom-color:var(--indigo)}
/* The category rides under the item rather than in a column of its own. It
   qualifies the name — a "Wire" and a "Kit" are never confusable once you can
   read the name — so it does not deserve a seventh column's width. */
td.who .cat{
  display:block;font-family:var(--mono);font-size:10px;letter-spacing:.1em;
  text-transform:uppercase;color:var(--wire);margin-top:3px;
}
table.ct.stk td.d{text-align:right;white-space:nowrap}

/* One item's movements: a date, two words and a number. */
table.ct.mv{min-width:560px}
table.ct.mv td.who{text-align:left}
table.ct.mv td.ty{white-space:nowrap}

.crumb{margin:26px 0 0;font-family:var(--mono);font-size:11.5px;letter-spacing:.06em}
.crumb a{text-decoration:none;color:var(--wire)}
.crumb a:hover{color:var(--ink)}

/* What to reorder. A list rather than a table: it is three facts per line and
   the point is to read down it, not to compare columns. */
.restock{padding:4px 20px}
.restock ul{list-style:none;margin:0;padding:0}
.restock li{
  display:flex;align-items:baseline;gap:12px;flex-wrap:wrap;
  padding:12px 0;border-bottom:1px solid var(--rule);
}
.restock li:last-child{border-bottom:0}
.restock a{text-decoration:none;border-bottom:1px solid transparent;font-size:14.5px}
.restock a:hover{border-bottom-color:var(--indigo)}
.restock .cat{
  font-family:var(--mono);font-size:10px;letter-spacing:.1em;
  text-transform:uppercase;color:var(--wire);
}
/* The count is the reason the line is here, so it takes the end of the row and
   the eye can run down it. */
.restock b{
  margin-left:auto;font-family:var(--mono);font-size:12px;font-weight:400;
  color:var(--clay);white-space:nowrap;
}
.restock b.gone{color:var(--paper);background:var(--clay);padding:2px 7px;border-radius:2px}

/* Three states, and only two of them are worth ink. "In hand" is the ordinary
   case and the one most rows are in, so it is drawn at the weight of a note
   rather than a badge — a page where every line shouts says nothing. */
.pill.ok{border-color:var(--rule);color:var(--wire)}
.pill.low{border-color:rgba(181,101,29,.5);color:var(--clay)}
.pill.out{border-color:var(--clay);background:var(--clay);color:var(--paper)}

@media (max-width:620px){
  .restock b{margin-left:0}
}

/* ------------------------------------------------------------ alerts --- */

/* Five priorities, and the ink is spent from the top down. P0 is the sheet
   losing a patient, so it is filled; P1 costs money, so it is outlined in the
   same colour; the rest are notes and are drawn as notes. Grading them this
   way is the whole reason the tab sorts by priority — a list where every line
   looks equally urgent is a list nobody reads twice. */
.pill.p0{border-color:var(--clay);background:var(--clay);color:var(--paper)}
.pill.p1{border-color:rgba(181,101,29,.5);color:var(--clay)}
.pill.p2{border-color:var(--indigo);color:var(--indigo)}
.pill.p3,.pill.p4{border-color:var(--rule);color:var(--wire)}

/* Each figure here is labelled with what its priority means, which is two
   lines for some of them and one for the rest. Reserving the second line
   everywhere keeps the five counts on one baseline: a row of figures that
   staggers is a row the eye cannot run along. */
.tot.prio dt{min-height:3.1em}

/* Three columns, one of them a sentence and one of them a longer sentence, so
   the table is narrower than the contracts one and lets its last column wrap
   rather than pushing the page sideways. */
table.ct.al{min-width:720px}
table.ct.al td{vertical-align:top}
table.ct.al td.who{line-height:1.45}
table.ct.al td.det{
  text-align:left;font-size:13px;line-height:1.5;color:var(--wire);
}
table.ct.al td.det a{color:var(--ink);text-decoration:none;
  border-bottom:1px solid var(--rule)}
table.ct.al td.det a:hover{border-bottom-color:var(--indigo)}

/* The nine rules, and what each of them found. Same list shape as the restock
   panel: a badge, a line of prose, and the count that is the reason to look. */
.rules{padding:4px 20px}
.rules ul{list-style:none;margin:0;padding:0}
.rules li{
  display:flex;align-items:baseline;gap:14px;
  padding:13px 0;border-bottom:1px solid var(--rule);
}
.rules li:last-child{border-bottom:0}
.rules .what{display:block}
.rules .what b{display:block;font-weight:500;font-size:14.5px}
.rules .note{display:block;color:var(--wire);font-size:13px;margin-top:2px}
/* "clear" is the answer most of these give most days, so it is set as quietly
   as it deserves and only a count breaks out of the grey. */
.rules > ul > li > b{
  margin-left:auto;font-family:var(--mono);font-size:12px;font-weight:400;
  color:var(--wire);white-space:nowrap;
}
.rules > ul > li > b.hit{color:var(--clay)}

@media (max-width:620px){
  .rules li{flex-wrap:wrap}
  .rules > ul > li > b{margin-left:0}
}

/* -------------------------------------------------------------- time -- */

/* Where the working day goes. One bar a period, in two bands: travel on the
   floor and appointments above it.

   Stacked rather than side by side, which is what separates this chart from
   the money one it otherwise resembles. There, billed and received are two
   answers to be compared — the gap between the pair IS the reading. Here the
   two bands are parts of one day, and the height of the whole bar is the
   figure: a fourteen-hour Tuesday should look tall, not like two medium bars.

   Travel goes underneath because it is the part of the day that was never at
   a chair. Along the bottom of the plot it reads as one band across the whole
   period; capping each bar with it instead would make it a jagged line nobody
   can follow. */
.stack{margin-top:4px;padding-top:64px}
.stack-plot{
  display:flex;align-items:flex-end;gap:2px;height:150px;
  border-bottom:1px solid var(--rule);
}
.scol{
  position:relative;flex:1 1 0;height:100%;
  display:flex;flex-direction:column-reverse;justify-content:flex-start;
}
/* No min-height on either band, unlike the single-series charts. A floor of a
   pixel would draw a sliver of appointment time on a day that had none —
   every visit untimed — which is the one thing this chart must not do. */
.scol i{display:block;width:100%;height:var(--h)}
.scol i.tv{background:var(--wire);opacity:.42}
.scol i.ch{background:var(--indigo);opacity:.85}
.scol:hover i.tv,.scol:focus-visible i.tv{opacity:.62}
.scol:hover i.ch,.scol:focus-visible i.ch{opacity:1}
.scol:focus{outline:none}
.scol:focus-visible{outline:1px solid var(--indigo);outline-offset:2px}

/* The tooltip is the money chart's three-line one; it is anchored off --h,
   which on a stacked bar is the height of the whole column. */
.scol .mbar-tip{
  position:absolute;left:50%;bottom:calc(var(--h) + 6px);transform:translateX(-50%);
  white-space:normal;width:max-content;max-width:170px;
  line-height:1.5;text-align:left;padding:6px 9px;
}
.scol .mbar-tip > span{display:block}
.scol.at-start .mbar-tip{left:0;transform:none}
.scol.at-end .mbar-tip{left:auto;right:0;transform:none}
.scol:hover .mbar-tip,.scol:focus-visible .mbar-tip{opacity:1;visibility:visible}

.ckey i.ch{background:var(--indigo);opacity:.85}
.ckey i.tv{background:var(--wire);opacity:.42}

/* The same two bands again, a row at a time. .fbar stacks its fill because it
   only ever had one; two of them have to lie along it instead. Not a
   percentage of the row's own total but of the longest period in the table, so
   a quiet week is a short bar — a row-normalised one would draw every period
   full and say only which way the split fell. */
.fbar.duo{display:flex;align-items:stretch}
.fbar.duo i{flex:0 0 auto;height:3px}
.fbar.duo i.ch{background:var(--indigo)}
.fbar.duo i.tv{background:var(--wire);opacity:.55}

/* Eight columns, two of them hours and two of them counts. Narrower than the
   money tables because nothing in it is a ten-digit rupee figure. */
table.ct.tm{min-width:900px}
table.ct.tm td.who{white-space:nowrap}
table.ct.tm tfoot td{
  border-top:1px solid var(--ink);border-bottom:0;padding-block:13px 0;
  font-weight:500;
}
table.ct.tm tfoot td.who{font-family:var(--mono);font-size:10px;
  letter-spacing:.12em;text-transform:uppercase;color:var(--wire)}

@media (max-width:560px){
  .stack-plot{height:120px}
}
