/* ==========================================================================
   sada.css — everything added on top of the design handoff.
   assets/site.css is the handoff's canonical token file and stays unmodified,
   so anything invented for this build lives here instead.

   Two sections:
     1. COMPONENTS  — permanent site furniture (the leadership board).
     2. DRAFT MODE  — the watermark and placeholder markers. Self-disabling:
                      everything here is gated on html:not([data-env="live"]).
   ========================================================================== */


/* ==========================================================================
   1. COMPONENTS
   ========================================================================== */

/* Screen-reader-only label. The theme button is icon-only, so its accessible
   name has to come from somewhere that is not the title attribute. */
.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Nav right-hand cluster. .nav-row is `justify-content: space-between`, so the
   actions have to be one flex child or the CTA and the toggle drift apart. */
.nav-actions {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
}

/* Light / dark toggle. Circular to echo .brand-mark, and sized to match the
   height of .nav-cta beside it. */
.theme-toggle {
  display: inline-grid;
  place-items: center;
  width: 40px; height: 40px;
  padding: 0;
  border: 1px solid var(--line-strong);
  border-radius: 50%;
  background: transparent;
  color: var(--ink);
  cursor: pointer;
  transition: background-color .25s, border-color .25s, color .25s;
}
.theme-toggle:hover { background: var(--ink); color: var(--bg); border-color: var(--ink); }
.theme-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* Show the icon for the theme the button will switch TO, which is the
   convention users expect: a sun means "go light". Both icons are stacked in
   the same grid cell so the button never changes size on toggle. */
.theme-toggle .icon-sun,
.theme-toggle .icon-moon { grid-area: 1 / 1; }
.theme-toggle .icon-sun  { display: block; }  /* dark now -> offer light */
.theme-toggle .icon-moon { display: none; }
[data-theme="light"] .theme-toggle .icon-sun  { display: none; }
[data-theme="light"] .theme-toggle .icon-moon { display: block; }  /* light now -> offer dark */

/* The toggle stays available on mobile, unlike .nav-links and .nav-cta which
   the handoff hides below 900px. */
@media (max-width: 900px) {
  .theme-toggle { display: inline-grid; }
}

/* Leadership board — one card per director, each with its own portrait slot.
   Two columns rather than the handoff's single chairman block, because the
   client named two directors of equal standing and neither is a chairman. */
.board {
  display: grid;
  /* auto-fit, not a fixed two: a third director was added in September and a
     fixed pair left him alone on a second row looking like an afterthought.
     This holds two, three or four without another CSS change. */
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: var(--sp-6);
  margin-top: var(--sp-7);
  border-top: 1px solid var(--line);
  padding-top: var(--sp-7);
}
@media (max-width: 900px) { .board { grid-template-columns: 1fr; gap: var(--sp-7); } }

.board-member { display: flex; flex-direction: column; }

.board-member .board-photo {
  border-radius: var(--r-3);
  overflow: hidden;
  margin-bottom: var(--sp-5);
}

.board-member .board-name {
  font-family: var(--font-display);
  font-size: var(--step-2);
  font-weight: 400;
  letter-spacing: -0.02em;
  line-height: 1.1;
  color: var(--ink);
}

.board-member .board-role {
  font: 500 var(--step--2) var(--font-mono);
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--accent);
  margin-top: var(--sp-3);
}

.board-member .board-bio {
  color: var(--ink-dim);
  font-size: var(--step-0);
  margin-top: var(--sp-4);
  max-width: 44ch;
}


/* --------------------------------------------------------------------------
   Facility gallery.

   The photographs are candid phone shots in mixed orientations (some 3:4, some
   4:3), so every tile is forced to one aspect ratio with object-fit: cover.
   Letting them keep their own ratios produced a ragged grid that read as
   careless; cropping to a common shape reads as deliberate, and the full frame
   is one click away.
   -------------------------------------------------------------------------- */
.gallery {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
  gap: var(--sp-3);
  margin-top: var(--sp-7);
}

.gallery-item {
  position: relative;
  display: block;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: var(--r-2);
  overflow: hidden;
  background: var(--bg-elev);
  cursor: zoom-in;
  transition: border-color .25s, transform .25s;
}
.gallery-item:hover { border-color: var(--accent); transform: translateY(-3px); }
.gallery-item:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.gallery-item img {
  display: block;
  width: 100%;
  /* height:auto is what makes aspect-ratio work at all. Every <img> carries an
     HTML height attribute (added to reserve space before load), and that
     attribute is a presentational hint mapping to a DEFINITE height - with both
     dimensions definite, aspect-ratio is ignored. Without this line a 615x820
     photograph rendered in a 251x820 box, so object-fit:cover showed a 41%-wide
     vertical slice of it. Undistorted, and missing half the picture. */
  height: auto;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  /* The photographs are dim and slightly flat straight off a phone. A small
     lift here is grading, not deception - no content is altered. */
  filter: saturate(1.05) contrast(1.04);
  transition: transform .4s ease;
}
.gallery-item:hover img { transform: scale(1.03); }

.gallery-cap {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  padding: 22px 12px 10px;
  font: 500 var(--step--2) var(--font-mono);
  letter-spacing: .06em;
  color: #fff;
  background: linear-gradient(to top, rgba(0,0,0,.72), rgba(0,0,0,0));
  opacity: 0;
  transition: opacity .25s;
}
.gallery-item:hover .gallery-cap,
.gallery-item:focus-visible .gallery-cap { opacity: 1; }

/* Lightbox. A <dialog> rather than a hand-rolled overlay: the browser gives
   focus trapping, Esc-to-close and inertness of the page behind for free. */
dialog.lightbox {
  border: 0;
  padding: 0;
  background: transparent;
  max-width: 96vw;
  max-height: 96vh;
  overflow: visible;
}
dialog.lightbox::backdrop { background: rgba(0, 0, 0, .88); }
dialog.lightbox img {
  display: block;
  max-width: 96vw;
  max-height: 84vh;
  width: auto; height: auto;
  border-radius: var(--r-2);
}
dialog.lightbox .lb-cap {
  margin-top: var(--sp-3);
  font: 500 var(--step--1) var(--font-mono);
  letter-spacing: .06em;
  color: #EFEAE0;
  text-align: center;
  max-width: 70ch;
  margin-inline: auto;
}
dialog.lightbox .lb-close {
  position: absolute;
  top: -14px; right: -14px;
  width: 38px; height: 38px;
  border-radius: 50%;
  border: 1px solid rgba(255,255,255,.35);
  background: #0B1B2B;
  color: #EFEAE0;
  font-size: 17px; line-height: 1;
  cursor: pointer;
}
.lb-close:hover { border-color: #fff; }

/* Real photography dropped into a slot the handoff drew as a .ph placeholder.
   Matches .ph's radii and ratios so the surrounding layout does not shift. */
.photo {
  display: block;
  width: 100%;
  /* Same reason as .gallery-item img above: the HTML height attribute makes the
     height definite, which silently disables every aspect-ratio below. */
  height: auto;
  border-radius: var(--r-3);
  object-fit: cover;
  filter: saturate(1.05) contrast(1.04);
}
.photo.tall  { aspect-ratio: 3 / 4; }
.photo.wide  { aspect-ratio: 16 / 9; }
.photo.square{ aspect-ratio: 1; }
.photo.hero-photo { aspect-ratio: 5 / 4; }

/* --------------------------------------------------------------------------
   Certification document (the ISO 9001:2015 certificate on /quality).

   The scan reuses .gallery-item so it inherits the lightbox for free, but two
   of that class's rules are wrong for a document and are undone here:
     - aspect-ratio 4/5 + object-fit cover would CROP the certificate, which
       for a document is not a crop but a misrepresentation;
     - the saturate/contrast lift is photo grading, and grading a certificate
       is exactly the kind of alteration a document must never receive.
   -------------------------------------------------------------------------- */
.cert-doc {
  display: grid;
  grid-template-columns: minmax(220px, 300px) 1fr;
  gap: var(--sp-6);
  align-items: start;
  margin-top: var(--sp-6);
}
@media (max-width: 820px) {
  .cert-doc { grid-template-columns: 1fr; gap: var(--sp-5); }
  .cert-shot { max-width: 320px; }
}

.cert-shot img {
  aspect-ratio: auto;      /* show the whole document, never a crop */
  /* height:auto is load-bearing, not tidiness. .gallery-item img sets
     width:100% and relies on aspect-ratio for its height; removing the
     aspect-ratio without this makes the box fall back to the HTML height
     attribute (1766px), so the certificate rendered 298 wide by 1766 tall. */
  height: auto;
  object-fit: contain;
  filter: none;            /* no grading on a certificate */
  background: #fff;
}
.cert-shot:hover img { transform: none; }

.cert-shot-note {
  display: block;
  margin-top: 10px;
  font: 500 var(--step--2) var(--font-mono);
  letter-spacing: .06em;
  color: var(--ink-dim);
}

/* One chip in the home page's .cert-strip now points at real evidence rather
   than restating a claim, so it is a link. Everything else about it matches
   the surrounding chips - a differently-styled chip would read as a button. */
.cert-chip-link {
  color: var(--ink);
  text-decoration: none;
  transition: border-color .2s, color .2s;
}
.cert-chip-link:hover,
.cert-chip-link:focus-visible { border-color: var(--accent); color: var(--accent); }

/* The certificate's own fields, transcribed verbatim so the page can be read
   without opening the scan and so the values are selectable and searchable. */
.cert-facts { margin: 0; }
.cert-facts > div {
  display: grid;
  grid-template-columns: minmax(140px, 200px) 1fr;
  gap: var(--sp-2) var(--sp-4);
  padding: 12px 0;
  border-bottom: 1px solid var(--line);
}
.cert-facts > div:first-child { border-top: 1px solid var(--line); }
.cert-facts dt {
  font: 500 var(--step--2) var(--font-mono);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink-dim);
}
.cert-facts dd { margin: 0; color: var(--ink); }
.cert-facts dd .mono { font-family: var(--font-mono); letter-spacing: .04em; }
@media (max-width: 560px) {
  .cert-facts > div { grid-template-columns: 1fr; }
}


/* ==========================================================================
   2. DRAFT MODE
   Shown by DEFAULT. site.js stamps data-env="live" on <html> only when the
   page is served from the production hostname, so the fail-safe direction is
   "watermark stays in": forgetting to configure something can never silently
   ship an unwatermarked draft.
   ========================================================================== */

/* Diagonal repeating agency credit across the whole viewport.

   On html::after, not body::after: site.css sets `overflow-x: clip` on body,
   which in some engines clips fixed-position descendants. <html> has no such
   clip, so the overlay is reliably full-viewport.

   pointer-events: none so it never intercepts a click.

   Tile geometry is sized so the whole phrase fits rather than clipping at the
   tile edge: at font-size 22 with letter-spacing 4, monospace runs ~17px per
   character, so 25 characters need ~430px. Rotated -24 degrees that occupies
   ~393px across and ~175px up, which clears a 560x280 tile from the (12,190)
   baseline. A credit that reads "Developed by binaryh" is worse than none. */
html:not([data-env="live"])::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 9998;
  pointer-events: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='560' height='280'%3E%3Ctext x='12' y='190' transform='rotate(-24 12 190)' font-family='monospace' font-size='22' letter-spacing='4' fill='%23ffffff'%3EDeveloped by binaryhat.ai%3C/text%3E%3C/svg%3E");
  background-repeat: repeat;
  /* Low enough to read the design through, high enough to be unmistakable in
     a screenshot. */
  opacity: .08;
}

/* The tile above is white, which is invisible on the light palette's bone
   background. Restate it in ink for light mode. Both themes must carry a
   visible watermark or the toggle becomes a way to defeat it. */
html[data-theme="light"]:not([data-env="live"])::after {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='560' height='280'%3E%3Ctext x='12' y='190' transform='rotate(-24 12 190)' font-family='monospace' font-size='22' letter-spacing='4' fill='%230B1B2B'%3EDeveloped by binaryhat.ai%3C/text%3E%3C/svg%3E");
  opacity: .10;
}

/* Persistent corner badge, so the state is unambiguous even in a cropped
   screenshot where the diagonal tiling might not be obvious. */
html:not([data-env="live"])::before {
  content: "DRAFT SITE - CONTENT NOT FINAL";
  position: fixed;
  left: 0;
  bottom: 0;
  z-index: 9999;
  pointer-events: none;
  font: 500 11px/1 var(--font-mono, monospace);
  letter-spacing: .14em;
  padding: 9px 14px;
  color: #0B1B2B;
  background: var(--accent-2, #E8C56B);
  border-top-right-radius: var(--r-2, 8px);
}

@media print {
  html:not([data-env="live"])::after { opacity: .16; }
}

/* --------------------------------------------------------------------------
   Placeholder markers.

   .tbd wraps any value that is NOT client-supplied — an invented figure, an
   unconfirmed contact detail, copy written to fill a slot. It renders as a
   dashed amber chip so a reviewer can see at a glance what still needs real
   content, and the title attribute says what is needed.

   On the live site these markers go inert (the rules below are gated), so a
   forgotten .tbd degrades to ordinary text rather than leaking "TBD" to the
   public. The audit ledger, not the CSS, is the record of what is outstanding.
   -------------------------------------------------------------------------- */
html:not([data-env="live"]) .tbd {
  background: color-mix(in oklab, var(--accent-2) 16%, transparent);
  border-bottom: 1px dashed var(--accent-2);
  border-radius: 2px;
  padding: 0 3px;
  cursor: help;
}

/* Markers that could not be matched to a checklist entry keep a plain "TBD"
   flag, so an unlinked marker is still visibly flagged rather than silently
   losing its annotation. Matched ones get their number instead, below. */
html:not([data-env="live"]) .tbd:not([data-ck-ref])::after {
  content: "TBD";
  display: inline-block;
  vertical-align: super;
  margin-left: 4px;
  font: 500 9px/1 var(--font-mono, monospace);
  letter-spacing: .1em;
  color: var(--accent-2);
  text-transform: none;
}

/* ── The numbered checklist reference ──────────────────────────────────────
 *
 * Rendered as GENERATED CONTENT on the marker itself, never as an injected
 * element. A review of all 169 placements showed why that distinction matters:
 * an extra inline element becomes a flex/grid item and tears apart .role,
 * .api-row, .prose .checklist li and .split-item h4; it nests an <a> inside a
 * <button> and inside .role anchors, which is invalid HTML; and it rides along
 * in copied text, so copying the phone number yielded "+91 80080 3736581" on
 * the one page whose entire purpose is copying values out to correct them.
 *
 * Generated content is never copied, never focusable, and never a layout item,
 * so all of that disappears. The number lives in data-ck-ref; assets/site.js
 * makes the marker clickable.
 *
 * The "#" is load-bearing, not decoration: markers routinely wrap a value that
 * already ends in a digit ("Gastrointestinal · 6"), and a bare number butted
 * against it read as "· 69".
 */
html:not([data-env="live"]) .tbd[data-ck-ref] {
  cursor: pointer;
}
html:not([data-env="live"]) .tbd[data-ck-ref]::after {
  content: "#" attr(data-ck-ref);
  display: inline-block;
  vertical-align: super;
  /* Symmetric gutters. The left one keeps the badge off a preceding digit; the
     right one keeps it off sentence-final punctuation, which otherwise ends up
     stranded on the far side of the pill. */
  margin: 0 3px 0 6px;
  padding: 2px 5px;
  border-radius: var(--r-1, 4px);
  background: var(--accent-2);
  color: #0B1B2B;
  font: 500 9px/1.4 var(--font-mono, monospace);
  letter-spacing: .04em;
  text-transform: none;
  user-select: none;
}
html:not([data-env="live"]) .tbd[data-ck-ref]:hover::after { background: var(--accent); }

/* Block markers pin their reference to the top-right corner, OUT OF FLOW.
   Absolute positioning is the point: as an in-flow child it became a third
   grid item in .prose .checklist li (a 24px 1fr grid), a fourth flex item in
   .split-item h4, and it welded to the last word - "IndiaChecklist #80". Out
   of flow it can do none of those things, in any container. */
html:not([data-env="live"]) .tbd-block[data-ck-ref] {
  position: relative;
  cursor: pointer;
}
html:not([data-env="live"]) .tbd-block[data-ck-ref]::after {
  content: "Checklist #" attr(data-ck-ref);
  position: absolute;
  top: 6px;
  right: 8px;
  padding: 3px 8px;
  border-radius: var(--r-1, 4px);
  background: var(--accent-2);
  color: #0B1B2B;
  font: 500 10px/1.3 var(--font-mono, monospace);
  letter-spacing: .04em;
  text-transform: none;
  user-select: none;
  pointer-events: none;
}
html:not([data-env="live"]) .tbd-block[data-ck-ref]:hover::after { background: var(--accent); }

/* Nothing to hide on the production hostname: with no injected element and the
   badges gated on :not([data-env="live"]), the reference leaves no trace. */

/* Block-level variant for whole paragraphs and cards, where an inline chip
   would look like a typo rather than a annotation. */
html:not([data-env="live"]) .tbd-block {
  border-left: 2px solid var(--accent-2);
  padding-left: var(--sp-4);
  background: color-mix(in oklab, var(--accent-2) 7%, transparent);
}

/* Anything that exists only for the review cycle. Note the polarity is the
   reverse of the rules above: this is hidden when live rather than shown when
   draft, so it stays out of the production DOM's flow entirely. */
html[data-env="live"] .draft-only { display: none !important; }

.draft-only {
  margin-top: var(--sp-6);
  padding: var(--sp-4) 0;
  border-top: 1px dashed var(--accent-2);
}
.draft-only a {
  font: 500 var(--step--2) var(--font-mono);
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--accent-2);
}
.draft-only a:hover { text-decoration: underline; }

/* The handoff's image placeholders already carry a data-label. In draft mode
   tint their border amber too, so photography reads as outstanding alongside
   every other placeholder rather than as a separate category. */
html:not([data-env="live"]) .ph {
  border-color: color-mix(in oklab, var(--accent-2) 45%, transparent);
}


/* --------------------------------------------------------------------------
   Arriving from the checklist (SP-52).

   The checklist highlights its own cards with :target when you travel the other
   way; this is the same mechanism pointed back, so there is one idea here and
   not two. Draft mode only - on the live site the markers do not exist, so
   neither does this.

   scroll-margin-top clears the sticky nav. Without it the browser scrolls the
   target to y=0, where the header sits on top of it, and the client is looking
   at the right place while seeing the wrong thing.
   -------------------------------------------------------------------------- */
html:not([data-env="live"]) [id^="ck-i"],
html:not([data-env="live"]) .ck-hit {
  scroll-margin-top: 120px;
}
/* .ck-hit is applied by initChecklistTarget. :target alone is not enough for the
   nav and footer items, whose id is set by script AFTER the fragment was
   resolved - a browser does not necessarily re-run :target for an id that
   appears later. Same styling, so the reader cannot tell which path was taken. */
html:not([data-env="live"]) [id^="ck-i"]:target,
html:not([data-env="live"]) .ck-hit {
  background: color-mix(in oklab, var(--accent) 22%, transparent);
  box-shadow: 0 0 0 4px color-mix(in oklab, var(--accent) 22%, transparent);
  border-radius: 2px;
  animation: ck-found 2.4s ease-out 1;
}
@keyframes ck-found {
  0%, 55% { background: color-mix(in oklab, var(--accent) 48%, transparent); }
  100%    { background: color-mix(in oklab, var(--accent) 22%, transparent); }
}
@media (prefers-reduced-motion: reduce) {
  html:not([data-env="live"]) [id^="ck-i"]:target,
  html:not([data-env="live"]) .ck-hit { animation: none; }
}


/* --------------------------------------------------------------------------
   Section anchors (SP-61).

   The nav is sticky, so a fragment link scrolls its target to y=0 and the header
   sits on top of it - the reader arrives at the right place and sees the wrong
   thing. The checklist anchors already handle this; the SECTION anchors never
   did, and there are several already in use: #capabilities, #certification,
   #facility, #laboratory, #reagents.

   Not gated on draft mode: unlike the marker anchors, these are permanent
   navigation and matter more once the site is live.
   -------------------------------------------------------------------------- */
section[id] {
  scroll-margin-top: 100px;
}


/* --------------------------------------------------------------------------
   Figure placeholders are draft chrome too (SP-64).

   Everything else in section 2 is gated on :not([data-env="live"]), but .ph
   comes from the locked handoff site.css, which knows nothing about draft mode
   and renders every placeholder the same way everywhere: a hatched box
   captioned with its data-index and data-label. On the production hostname
   that puts "FIG - 01 / ANALYTICAL LABORATORY - FULL BLEED" across half of a
   section, which is the most conspicuous draft marking on the site and the one
   nobody had noticed, because nobody had looked at a page with data-env="live"
   on it until now.

   THREE RULES, AND THE ORDER OF THEM MATTERS.

   The first is the one that must never fail: hide the placeholder itself. It is
   a plain selector on purpose, so it still applies in a browser without :has()
   support - where the two below are dropped as unknown selectors. The fail-safe
   direction here is "caption never ships", even at the cost of layout.

   The second and third repair the layout that the first leaves behind. A split
   whose media column is entirely placeholders would otherwise render as text in
   one narrow column beside half a page of nothing; collapsing the column and
   the grid with it makes the section read as a deliberate full-width text
   block. Scoped with :has(.ph) so a split whose photographs HAVE been supplied
   is untouched - as each one is supplied, its section returns to two columns on
   its own with no further edit here.

   WHAT THIS DOES NOT DO. It does not make the page finished. A leadership card
   whose portrait is missing still loses its photograph and sits next to one
   that has it, and the prose in these slots still reads "to be supplied". This
   rule removes the marking, which is all it can do; the photographs are content
   and have to be supplied.
   -------------------------------------------------------------------------- */
html[data-env="live"] .ph { display: none !important; }
html[data-env="live"] .split > *:has(.ph) { display: none; }
html[data-env="live"] .split:has(.ph) { grid-template-columns: 1fr; }
html[data-env="live"] .board-photo:has(.ph) { display: none; }
