/* ==========================================================================
   Discoverer theme override for the compiled EasyCore bundle — DARK.

   Loaded AFTER styles.<hash>.css. The compiled app is CSS-custom-property
   themed, so overriding the :root block reaches all 19 var() consumers
   (8 in styles.css, 11 in the inlined component styles inside main.<hash>.js),
   and every remaining surface is reachable through a public class name.

   Two rules for anything added here:
   - Only target stable public class names (.btn, .logo, .modal, .sidebar, ...).
     Angular rewrites the [_ngcontent-%COMP%] attribute to a per-build hash at
     runtime, so those attribute selectors can never be matched from this file.
   - Component styles ship at specificity 0,2,0 (.class[attr]), so overrides
     that must beat them need !important.

   Design source of truth:
   ~/cal-claude-code/pencil/discoverer.pen — frames "EasyCore — Upload /
   Details Modal / Crop & Rename / Crop Applied / Adjust Crop / Download
   (Discoverer)". Palette variables come from that file's `variables` block,
   which agrees with dgex/discoverer/html/theme/css/brand-tokens.css.
   Gold is #FCB722 (PMS 1235 C). #F9A900 is banned drift — do not reintroduce.

   What this file does NOT do: the pen screens also add markup the compiled app
   does not have — a 340px right rail (video card, HOW IT WORKS steps, privacy
   badge), a hero eyebrow/headline/subhead above the dropzone, per-card tool
   icon rows and DISCOVERER tags. Those are structure, not style; they land in
   the React rebuild (app/frontend-next), not here.
   ========================================================================== */

/* --- Self-hosted brand fonts --------------------------------------------- */
@font-face {
  font-family: "Founders Grotesk";
  src: url("assets/fonts/founders-grotesk-regular.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Founders Grotesk";
  src: url("assets/fonts/founders-grotesk-semibold.woff2") format("woff2");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}
@font-face {
  /* Single Medium file serves the whole range; Druk is only used at weight 500. */
  font-family: "Druk Wide";
  src: url("assets/fonts/DrukWide-Medium-Web.woff2") format("woff2");
  font-weight: 400 700;
  font-style: normal;
  font-display: swap;
}

/* --- Tokens --------------------------------------------------------------- */
:root {
  /* --primary is used by the bundle as BOTH text color and fill. On the old
     light scheme that ruled gold out (1.76:1 on white); with every surface now
     dark, gold clears 10:1 everywhere it lands, so --primary can finally BE the
     brand colour and the 8 consumers come out right for free. */
  --primary: #fcb722;

  --textDefault: #aaaaa0; /* $concrete — body ink, 8.97:1 on black */
  --textDark: #ffffff;    /* $white — heading/input ink */
  --white: #ffffff;
  --black: #000000;
  --bgLight: #151515;     /* $carbon — panel fill; header is darkened below */

  /* Pen palette, verbatim from discoverer.pen `variables`. */
  --dg-gold: #fcb722;
  --dg-gold-hover: #ffc94e; /* lifts on dark; the light theme's #e0a600 sinks */
  --dg-page: #000000;
  --dg-chrome: #0d0d0d;     /* header bar */
  --dg-footer: #0a0a0a;
  --dg-dropzone: #0f0f10;
  --dg-carbon: #151515;     /* cards, sidebar panels */
  --dg-panel-head: #1a1a1a;
  --dg-field: #0c0c0c;      /* input wells */
  --dg-iron: #3c3c3e;       /* decorative hairlines only — 1.9:1, cannot carry state */
  --dg-steel: #576167;
  --dg-concrete: #aaaaa0;
  --dg-aluminium: #b4bcbc;  /* field labels, 9.44:1 on carbon */
  --dg-dirty-white: #ececea;

  /* Accessibility-derived, not brand colours:
     - $steel is used in the pen for muted text ("No file selected yet", "Total
       size"). It measures 2.88:1 on carbon, so text never gets it here —
       $concrete does. Steel survives only as a border that must carry state
       (3.2:1 on the dropzone, clearing WCAG 1.4.11's 3:1).
     - Disabled ink: the bundle leaves disabled buttons at var(--white) over a
       near-panel fill. #8a9095 is 5.39:1 on the disabled fill. */
  --dg-ink-disabled: #8a9095;
  --dg-disabled-fill: #1a1a1a;

  --dg-font-body: "Founders Grotesk", system-ui, -apple-system, "Segoe UI", sans-serif;
  --dg-font-display: "Druk Wide", system-ui, -apple-system, "Segoe UI", sans-serif;
}

/* --- Page ----------------------------------------------------------------- */
/* styles.css hardcodes background-color:#fff and color:#636363 on html,body —
   both have to be overridden by value, not by token. */
html,
body {
  font-family: var(--dg-font-body);
  background-color: var(--dg-page);
  color: var(--dg-concrete);
}

/* normalize.css paints <hr> with a hardcoded #dedede; the footer uses one as a
   rule above the copyright line. */
hr {
  background-color: var(--dg-iron) !important;
}

/* --- Typography ----------------------------------------------------------- */
/* Druk Wide is very wide and is always uppercase at weight 500. Restricted to
   h1/h2 — on h3/h4 it wraps strings like "Easy Core Imaging Tool Feedback Form"
   into an unreadable stack inside the 400px modals. */
h1,
h2 {
  font-family: var(--dg-font-display);
  font-weight: 500;
  text-transform: uppercase;
  line-height: 1.05;
  letter-spacing: 0;
  color: var(--white);
}
h1 { font-size: 1.75rem; }
h2 { font-size: 1.25rem; }

/* The bundle paints modal headings with var(--primary) at 0,2,0 — now gold,
   which is the pen's eyebrow colour, not its title colour. Titles are white. */
.modal h2,
.popup-content h2 {
  color: var(--white) !important;
}

h3,
h4,
h5,
h6 {
  font-family: var(--dg-font-body);
  font-weight: 600;
}

/* The header title ships as .left h1 in 'Roboto Condensed' — the last remaining
   reference to a font we no longer load. It sits directly beside the Discoverer
   mark, so Druk Wide here would compete with the logo; Founders 600 keeps it as
   chrome. Specificity must beat the component's .left[attr] h1[attr]. The two
   #dedede divider rules beside it also come from that component. */
.left h1 {
  font-family: var(--dg-font-body) !important;
  font-weight: 600;
  color: var(--white) !important;
  border-left-color: var(--dg-iron) !important;
  border-right-color: var(--dg-iron) !important;
}

strong,
b {
  /* Founders Grotesk has no 700 face; "bold" is 600. The pen sets 700 on
     headings and labels — that renders as the Semibold face here. */
  font-weight: 600;
}

/* --- Links ---------------------------------------------------------------- */
/* Links inherit var(--primary), so they are already gold against concrete body
   text. The underline stays as a non-colour affordance. Buttons are excluded —
   some are <a class="btn btn-sm">. */
a:not(.btn) {
  text-decoration: underline;
  text-underline-offset: 2px;
}
a:not(.btn):hover,
a:not(.btn):focus {
  color: var(--dg-gold-hover);
  text-decoration-thickness: 2px;
}
/* The header's support link ships var(--textDefault) at 0,2,0. */
.left a {
  color: var(--dg-dirty-white) !important;
}

/* --- Chrome: header, footer ------------------------------------------------ */
/* The pen header is a #0D0D0D bar closed by a 2px gold rule. The component
   paints it var(--bgLight), which is carbon — one step too light for chrome. */
header {
  background-color: var(--dg-chrome) !important;
  border-bottom: 2px solid var(--dg-gold);
}

/* Vertical rhythm. The bundle runs tight — main at 1.5em and footer at 1em —
   which on a black page reads as cramped; the pen gives the upload column
   56px/72px and the footer 48px. Both selectors are element rules inside
   component styles (main[_ngcontent-c0], footer[_ngcontent-c4]) at specificity
   0,1,1, so a bare element selector here cannot reach them without !important. */
main {
  padding: 5em 0 !important;
}

footer {
  background-color: var(--dg-footer);
  border-top: 1px solid var(--dg-iron);
  color: var(--dg-concrete);
  padding-top: 5em !important;
}
.copyrightText {
  color: var(--dg-steel);
}

/* --- Buttons -------------------------------------------------------------- */
/* Gold fill with black text: 11.9:1. The bundle's own rule paints var(--white)
   on var(--primary), which is now white-on-gold at 1.7:1.
   CTAs are Druk Wide Medium, uppercase — Druk is NEVER set in mixed case.
   Sized down from the bundle's 1em: Druk is very wide, buttons ship
   white-space:nowrap, and the longest label ("Choose file to upload") would
   otherwise overrun the 400px modals. Padding is em-based so it scales with the
   type. The bundle's 1px letter-spacing is dropped to .02em — Druk carries its
   own width and does not need tracking on top. */
.btn,
button {
  background-color: var(--dg-gold) !important;
  color: var(--black) !important;
  border-color: transparent;
  font-family: var(--dg-font-display) !important;
  font-weight: 500 !important;
  text-transform: uppercase;
  font-size: .8125rem;
  letter-spacing: .02em;
}

.btn-sm {
  font-size: .75rem;
}

/* The floating video CTA card (thumbnail + "How-to Video Tutorial" + subtitle)
   is dropped — the pen has no such element above the dropzone, and the React
   rebuild removed it from the rail too. Nothing is orphaned: the header's own
   "Video Tutorial" link (a.videoTutorial) calls the same videoPopup() handler,
   so the video is still reachable. Hidden rather than deleted because the node
   is baked into the compiled template; the DOM removal lands with the rebuild. */
.videoButton {
  display: none !important;
}

/* Close controls are ×, not CTAs — Druk's multiply glyph is misshapen and they
   carry no brand weight. Sizes are left to the bundle, which centres the glyph
   with a hand-tuned line-height. */
.close,
.closeSignup,
.removeFile {
  font-family: var(--dg-font-body) !important;
  font-weight: 600 !important;
  text-transform: none;
  letter-spacing: 0;
}

/* .close and .removeFile are filled corner controls and keep the gold fill they
   inherit from the button rule — the pen draws exactly that: a gold square with
   a black ×. .closeSignup sits inside the modal and ships transparent; on dark
   it becomes an aluminium glyph. */
.closeSignup {
  background-color: transparent !important;
  color: var(--dg-aluminium) !important;
}
.closeSignup:hover,
.closeSignup:focus {
  background-color: transparent !important;
  color: var(--white) !important;
}

.btn:hover,
.btn:focus,
button:hover,
button:focus {
  /* The bundle's hover flips to a white fill with a gold border — a light-theme
     move that now flares against a black page. Hover lifts the gold instead. */
  background-color: var(--dg-gold-hover) !important;
  color: var(--black) !important;
  border-color: var(--dg-gold-hover) !important;
}
.btn[disabled],
button[disabled] {
  background-color: var(--dg-disabled-fill) !important;
  color: var(--dg-ink-disabled) !important;
  border-color: transparent !important;
  cursor: not-allowed;
}

/* --- Uploader: dropzone ---------------------------------------------------- */
/* .inner is reused by four components (uploader dropzone, editor card, video
   popup, form popup), so every rule for it is scoped by a public ancestor. */
.easycore-uploader .inner {
  background-color: var(--dg-dropzone);
}
.uploader-disclaimer {
  color: var(--dg-concrete);
}

/* Drag-and-drop target outline. The bundle draws 2px dashed var(--primary) at
   opacity .5, animating to 1 on .inner:hover and .ondragover — that opacity IS
   the dropzone's only affordance, so it is left alone. Gold at rest .5 over
   #0F0F10 is an effective ~4.6:1, well past the 3:1 that WCAG 1.4.11 wants for
   a non-text state indicator, so the pen's flat iron border is deliberately not
   used here: iron is 1.7:1 and would kill the affordance. */
.border {
  border-color: var(--dg-gold) !important;
}
/* Bundle fills the drag-over state with #ddd — a light-theme wash. */
.ondragover .border {
  background-color: rgba(252, 183, 34, .08) !important;
}

/* --- Editor: image cards --------------------------------------------------- */
/* Pen card: carbon fill, 1px iron hairline, no shadow. The bundle ships
   var(--white) plus a #eee border and a drop shadow tinted with
   var(--textDefault), all of which read as light-theme lift. */
.easycore-editor .image .inner {
  background-color: var(--dg-carbon) !important;
  border: 1px solid var(--dg-iron) !important;
  box-shadow: none !important;
}
.easycore-editor .meta {
  border-top-color: var(--dg-iron) !important;
}
.fileName {
  color: var(--dg-concrete);
  font-size: .75rem;
  line-height: 1.3;
}
/* Selected-file ring — the only thing distinguishing a selected thumbnail.
   Gold on carbon is 10.4:1. */
.selected {
  box-shadow: 0 0 0 2px var(--dg-gold) !important;
}
/* Drag handle and per-image controls are black-on-transparent SVG data URIs
   baked into the bundle; they vanish on carbon without an inversion. */
.handle,
.image_controls {
  filter: invert(1);
}
/* Loader plate is hardcoded #fff and flashes white between crops. */
.loading {
  background-color: var(--dg-field) !important;
}
.originalFileName {
  background-color: var(--dg-panel-head) !important;
  color: var(--dg-gold) !important;
}

/* --- Editor: sidebar panels ------------------------------------------------ */
/* Pen crop/rename panels: carbon body, 1px iron hairline, a #1A1A1A head strip
   carrying a gold step badge and a white uppercase title. */
.sidebar .fixer {
  background-color: var(--dg-carbon) !important;
  border: 1px solid var(--dg-iron);
}

/* Sticky sidebar, replacing the bundle's scroll-handler approach.
   The component parks the panel at position:static/top:0 and a scroll handler
   toggles .active -> {position:fixed; top:50px}, with `transition:all .3s` on
   top of it. Three problems, all visible: the swap from static to fixed pops
   the panel by 50px and the transition animates that pop (the jumpiness); a
   fixed element is out of flow, so nothing stops it running over the footer;
   and with only a few images the column is shorter than the panel, so the
   handler flips state repeatedly around the threshold.

   position:sticky fixes all three at once — it stays in flow, so it cannot
   cross its container, and it needs no scroll handler. Two conditions:
   - .sidebar must be able to travel. The editor row is align-items:flex-start,
     which shrink-wraps the column to the panel's own height, leaving zero
     sticky range; align-self:stretch gives it the full row height.
   - the .active rule must be beaten. It is not !important, so these are.
   The scroll handler still runs and still toggles the class; it just no longer
   has any effect. No ancestor sets overflow, so sticky is not clipped. */
.easycore-editor .sidebar {
  align-self: stretch !important;
}
.sidebar .fixer,
.sidebar .fixer.active {
  position: sticky !important;
  top: 1.5em !important;
  width: auto !important;
  transition: none !important;
  /* On short viewports a tall crop+rename panel would otherwise have its
     Download button parked below the fold with no way to reach it. */
  max-height: calc(100vh - 3em);
  overflow-y: auto;
}

/* h3 is the panel head. The bundle paints it var(--white) on var(--textDefault)
   — with textDefault now concrete that would be white on light grey. */
h3 {
  background-color: var(--dg-panel-head) !important;
  color: var(--white) !important;
  border-left: 3px solid var(--dg-gold);
  font-size: .875rem;
  font-weight: 600;
  letter-spacing: .06em;
}

.sidebar label {
  color: var(--dg-aluminium);
}

/* Field wells: near-black inset, iron hairline, white value, steel placeholder.
   Sidebar inputs ship border:none at 0,2,0, hence !important on the border. */
input[type="text"],
input[type="email"],
input[type="number"] {
  background-color: var(--dg-field) !important;
  border: 1px solid var(--dg-iron) !important;
  color: var(--white) !important;
}
input::placeholder {
  color: var(--dg-steel);
  opacity: 1; /* Firefox dims placeholders by default */
}
.inputText {
  color: var(--white) !important;
}

/* Checkboxes and radios render as light-theme OS controls on a black panel;
   accent-color repaints them gold with a black glyph in every current engine. */
input[type="checkbox"],
input[type="radio"] {
  accent-color: var(--dg-gold);
}

/* Focus indicator: the bundle ships 1px, too faint to serve as a focus ring.
   Thickened to 2px with an offset; gold is 11:1 on every dark surface. */
input[type="text"]:focus,
input[type="email"]:focus,
input[type="number"]:focus,
input[type="text"]:hover,
input[type="email"]:hover {
  outline: 2px solid var(--dg-gold) !important;
  outline-offset: 1px;
}

/* Range sliders in the lens-correction panel default to a light track. */
input[type="range"] {
  accent-color: var(--dg-gold);
}

/* --- Modals and popups ----------------------------------------------------- */
/* Pen modal: #0E0E10 body, 1px iron hairline, closed at the top by a 3px gold
   accent. Four containers share that treatment; all four hardcode #fff. */
.modal,
.popup-content,
.videopopupContainer,
.formpopupContainer {
  background-color: #0e0e10 !important;
  border: 1px solid var(--dg-iron) !important;
  border-top: 3px solid var(--dg-gold) !important;
  color: var(--dg-concrete);
}
/* The video/form popups also carry a 5px white frame and a light drop shadow. */
.videopopupContainer,
.formpopupContainer {
  box-shadow: 0 8px 60px -19px #000 !important;
}
/* Scrims sit at rgba(0,0,0,.5) — too weak to separate a dark modal from a dark
   page. */
.modalContainer,
.popup-background,
.videopopup,
.formpopup {
  background-color: rgba(0, 0, 0, .72) !important;
}

/* Status panel inside the download/processing screen: #f8f8f8 with a #ccc
   border in the bundle. */
.message-info {
  background-color: var(--dg-carbon) !important;
  border: 1px solid var(--dg-iron) !important;
  color: var(--dg-concrete) !important;
}
/* The status glyph is a data-URI SVG hardcoded to the old brand blue #2AABE1;
   it cannot be recoloured at source from here. Rotating hue to gold is the only
   reachable fix. The error variant is red and is left alone. */
.hourglass:not(.hourglass-error) {
  filter: hue-rotate(-160deg) saturate(1.6) brightness(1.15);
}

/* --- Feedback form popup ---------------------------------------------------- */
/* The form itself lives in a cross-origin <iframe> on hsforms.net and cannot be
   touched from here — its styling is injected through the embed's `css` option,
   patched into the bundle by tools/rebrand-bundle.sh. What IS reachable is the
   modal around it. */
.formpopupContainer h4,
.videopopupContainer h4 {
  color: var(--white);
  font-family: var(--dg-font-body);
  font-weight: 600;
  font-size: 1.125rem;
  margin: 0 0 1.25em;
}

/* Google renders its reCAPTCHA badge into the parent document too (HubSpot
   parks it in #hs-outer-captcha-target-0). Both copies are hidden. */
.grecaptcha-badge,
#hs-outer-captcha-target-0 {
  display: none !important;
}

/* Hiding the badge is only permitted if the reCAPTCHA attribution is shown
   instead, so it is printed under the form. This is a text-only substitute:
   generated content cannot carry the two links Google's sample markup uses, so
   the fully compliant version needs a real node in the modal — that lands with
   the React rebuild. */
.formpopupContainer .inner::after {
  content: "Protected by reCAPTCHA — the Google Privacy Policy and Terms of Service apply.";
  display: block;
  padding-top: 1em;
  color: var(--dg-steel);
  font-size: .6875rem;
  line-height: 1.4;
  text-align: center;
}

/* --- HubSpot cookie banner -------------------------------------------------- */
/* Injected by js.hs-scripts.com/2536834.js, so it is outside the Angular tree
   and outside the rebrand script's reach — but it is the first thing on the
   page, and it ships white with buttons in #2DACE1, the OLD Dynamics G-Ex blue,
   which comes from the portal's cookie-banner settings.

   Specificity: HubSpot writes its rules as
   `div#hs-eu-cookie-confirmation div#hs-eu-cookie-confirmation-inner a#hs-eu-…`
   (0,3,3) with !important, in a <style> appended to <head> at runtime — i.e.
   after this file, so anything equal loses the tie-break. The selectors below
   mirror that shape and add `html body` to clear it outright.

   This is a paint job. The real fix is to change the banner colours in portal
   2536834's settings; the portal itself stays untouched here because the
   backend CRM gate depends on it. */
html body div#hs-eu-cookie-confirmation {
  background: var(--dg-chrome) !important;
  border-top: none !important;
  border-bottom: 2px solid var(--dg-gold) !important;
  box-shadow: none !important;
  color: var(--dg-concrete) !important;
  font-family: var(--dg-font-body) !important;
}
html body div#hs-eu-cookie-confirmation div#hs-eu-cookie-confirmation-inner,
html body div#hs-eu-cookie-confirmation div#hs-eu-policy-wording,
html body div#hs-eu-cookie-confirmation div#hs-eu-policy-wording p,
/* The second paragraph is a sibling <p id="hs-eu-cookie-disclaimer">, not a
   child of the wording div — it keeps HubSpot's slate blue otherwise. */
html body div#hs-eu-cookie-confirmation p#hs-eu-cookie-disclaimer {
  background: transparent !important;
  color: var(--dg-concrete) !important;
  font-family: var(--dg-font-body) !important;
}
html body div#hs-eu-cookie-confirmation div#hs-eu-cookie-confirmation-inner a {
  color: var(--dg-gold) !important;
}
html body div#hs-eu-cookie-confirmation div#hs-eu-cookie-confirmation-inner a#hs-eu-confirmation-button,
html body div#hs-eu-cookie-confirmation div#hs-eu-cookie-confirmation-inner a#hs-eu-decline-button,
html body div#hs-eu-cookie-confirmation div#hs-eu-cookie-confirmation-inner a#hs-eu-cookie-settings-button {
  background-color: var(--dg-gold) !important;
  border: 1px solid var(--dg-gold) !important;
  border-radius: 0 !important;
  color: var(--black) !important;
  font-family: var(--dg-font-display) !important;
  font-weight: 500 !important;
  text-align: center !important;
  text-transform: uppercase;
  font-size: 12px !important;
}
/* Decline and Settings are the secondaries of the set — outline, not fill. */
html body div#hs-eu-cookie-confirmation div#hs-eu-cookie-confirmation-inner a#hs-eu-decline-button,
html body div#hs-eu-cookie-confirmation div#hs-eu-cookie-confirmation-inner a#hs-eu-cookie-settings-button {
  background-color: transparent !important;
  color: var(--dg-gold) !important;
}

/* --- Square corners -------------------------------------------------------- */
/* Discoverer runs hard-edged, and every pen frame is square. The bundle carries
   11 rounded declarations — .btn/button 6px, .modal/.popup-content 20px,
   .message-info/.inner/.videopopupContainer/.formpopupContainer 10px, and
   .close at 50px (circular). A blanket reset is used rather than 11 targeted
   overrides because most of those live in component styles whose
   [_ngcontent-*] hashes cannot be matched from here, and it also squares
   browser-default radii on form controls. */
*,
*::before,
*::after {
  border-radius: 0 !important;
}

/* --- Assets ---------------------------------------------------------------- */
/* The dropzone icon file itself is now gold ink (assets/image-upload-icon.png;
   the original black artwork is kept beside it as -black.png). It is 512x410
   where the original was 190x145, and the component constrains neither (.inner
   img only sets margin-bottom), so the width is pinned and the surplus
   resolution serves 2x displays. Matched on src rather than class: the only
   class in scope is .inner, which other components reuse. */
img[src*="image-upload-icon"] {
  width: 190px;
  height: auto;
}

/* The header mark (assets/discoverer-mark.png) is already gold-on-black and
   needs nothing. The footer wordmark is black artwork — inverted to white,
   which is what the pen footer shows. */
img[src*="discoverer-logo-black"] {
  filter: invert(1);
}

/* The Discoverer mark is 371x97 (3.82:1) where the old marks were 33x37 and
   211x90. The header's own component rule (.logo{height:30px;width:auto}) ships
   at specificity 0,2,0 and still wins there, so the header is left alone. The
   footer instance only sets margin-bottom, so without a cap it would render at
   its 371px intrinsic width. */
.logo {
  max-width: 240px;
  height: auto;
}
