/* ==========================================================================
   PDFCore Studio — Design Tokens
   --------------------------------------------------------------------------
   The single source of truth for typefaces, colour, type scale, spacing,
   radius, elevation and motion — shared by the marketing site, the tool
   workspace, the dashboard, the admin console and the auth pages.

   Every surface links this file first. Area stylesheets alias onto these
   tokens rather than declaring palettes of their own, so a brand change is
   one edit here instead of four.
   ========================================================================== */


/* --------------------------------------------------------------------------
   Typefaces — self-hosted, no runtime CDN (AGENTS.md §8.2)
   Both are variable fonts: one file per subset covers the whole weight range,
   and a declared weight above the range clamps down instead of shouting.
   -------------------------------------------------------------------------- */

@font-face {
  font-family: 'Schibsted Grotesk';
  font-style: normal;
  font-weight: 500 700;
  font-display: swap;
  src: url('/fonts/schibsted-grotesk-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Schibsted Grotesk';
  font-style: normal;
  font-weight: 500 700;
  font-display: swap;
  src: url('/fonts/schibsted-grotesk-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Public Sans';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/fonts/public-sans-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Public Sans';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/fonts/public-sans-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}


/* --------------------------------------------------------------------------
   Tokens — light is the default; dark overrides below.
   Arabic and Japanese fall through to the system stack, as they did before.
   -------------------------------------------------------------------------- */

:root {
  /* Typefaces */
  --font-display: 'Schibsted Grotesk', 'Segoe UI', system-ui, -apple-system, BlinkMacSystemFont, Roboto, Helvetica, Arial, sans-serif;
  --font-ui: 'Public Sans', 'Segoe UI', system-ui, -apple-system, BlinkMacSystemFont, Roboto, Helvetica, Arial, sans-serif;
  --font-mono: 'Consolas', 'Monaco', 'SF Mono', ui-monospace, monospace;
  --font-family: var(--font-ui);

  /* Type scale — 9 steps. The three largest are fluid. */
  --text-xs: 0.75rem;      /* 12 — labels, meta */
  --text-sm: 0.8125rem;    /* 13 — small copy */
  --text-base: 0.9375rem;  /* 15 — body */
  --text-md: 1.0625rem;    /* 17 — lead */
  --text-lg: 1.25rem;      /* 20 — card titles */
  --text-xl: 1.625rem;     /* 26 — sub-heads */
  --text-2xl: clamp(1.625rem, 1.15rem + 2.1vw, 2.125rem);  /* 26 → 34 — section titles */
  --text-3xl: clamp(2rem, 1.3rem + 3.1vw, 2.75rem);        /* 32 → 44 — page H1 */
  --text-4xl: clamp(2.25rem, 1.2rem + 4.6vw, 3.5rem);      /* 36 → 56 — hero */

  --leading-tight: 1.15;
  --leading-snug: 1.35;
  --leading-normal: 1.6;
  --tracking-tight: -0.03em;
  --tracking-snug: -0.02em;
  --tracking-wide: 0.12em;

  /* Spacing — 4px rhythm */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 24px;
  --space-6: 32px;
  --space-7: 48px;
  --space-8: 64px;
  --space-9: 96px;
  --section-py: 96px;
  --gutter: 24px;

  /* Radius — 12 controls, 16 cards, 20 panels */
  --radius-xs: 6px;
  --radius-sm: 8px;
  --radius-md: 12px;
  --radius-lg: 16px;
  --radius-xl: 20px;
  --radius-full: 9999px;

  /* Motion */
  --ease: cubic-bezier(0.16, 1, 0.3, 1);
  --dur-fast: 160ms;
  --dur-normal: 240ms;
  --transition-fast: 160ms cubic-bezier(0.16, 1, 0.3, 1);
  --transition-normal: 240ms cubic-bezier(0.16, 1, 0.3, 1);

  /* Layout */
  --max-width: 1200px;
  /* The header sits wider than body copy at the default step. Above it the two
     track together, because a nav narrower than the content beneath it reads
     as a misalignment rather than a choice. */
  --max-width-nav: 1440px;

  /* Surfaces */
  --bg-primary: #ffffff;
  --bg-secondary: #f8fafc;
  --bg-tertiary: #f1f5f9;
  --bg-card: #ffffff;
  --bg-card-hover: #f8fafc;
  --bg-glass: rgba(255, 255, 255, 0.86);
  --surface-card: #ffffff;
  --bg-panel: #ffffff;

  /* Borders */
  --border-color: #e2e8f0;
  --border-hover: #cbd5e1;
  --border-color-hover: #cbd5e1;  /* alias — a legacy rule misspells --border-hover */
  --border-glow: rgba(229, 72, 77, 0.20);

  /* Ink */
  --text-primary: #0f172a;
  --text-secondary: #475569;
  --text-muted: #64748b;
  --text-color: #0f172a;

  /* Brand — the only decorative colour */
  --accent-coral: #e5484d;
  --accent-coral-hover: #d13f44;
  --accent-coral-subtle: #fef2f2;
  --accent-coral-line: #fecdd3;
  --accent-coral-glow: rgba(229, 72, 77, 0.12);

  /* Semantic — these carry meaning and are never used as decoration */
  --accent-green: #059669;
  --accent-green-subtle: #ecfdf5;
  --accent-green-line: #a7f3d0;
  --accent-amber: #b45309;
  --accent-amber-subtle: #fffbeb;
  --accent-amber-line: #fde68a;
  --accent-blue: #1d4ed8;
  --accent-blue-subtle: #eff6ff;
  --accent-blue-line: #bfdbfe;
  --accent-teal: #0d9488;

  /* Per-tool accents, set inline by tool pages. Defaults so they never
     resolve to nothing. */
  --tool-color: var(--accent-coral);
  --tool-accent: var(--accent-coral);
  --tool-glow: var(--accent-coral-glow);

  /* Elevation — three tiers. A card gets a border AND one shadow, never
     a shadow plus a stripe plus a lift plus a gradient. */
  --shadow-xs: 0 1px 2px rgba(15, 23, 42, 0.04);
  --shadow-sm: 0 1px 3px rgba(15, 23, 42, 0.06), 0 1px 2px -1px rgba(15, 23, 42, 0.04);
  --shadow-md: 0 12px 28px -8px rgba(15, 23, 42, 0.10), 0 4px 10px -4px rgba(15, 23, 42, 0.06);
  --shadow-lg: 0 24px 56px -16px rgba(15, 23, 42, 0.16), 0 8px 20px -8px rgba(15, 23, 42, 0.08);
  --shadow-glow: none;

  /* Chart series — a fixed categorical order, assigned by entity and never
     cycled. These are separate from the semantic accents on purpose: the
     accents are tuned to sit next to body copy, chart marks are tuned to sit
     on the chart surface, and the two jobs want different lightness.

     Both ramps clear the six checks (lightness band, chroma floor, CVD
     separation, normal-vision floor, contrast) against this theme's card
     surface. Re-run the validator before changing a step. A single-series
     chart uses --chart-1 and needs no legend; the title names it. */
  --chart-1: #e5484d;
  --chart-2: #1d4ed8;
  --chart-3: #059669;
  --chart-4: #b45309;
  --chart-5: #0d9488;

  /* Grid and axes stay recessive — they orient, they do not compete. */
  --chart-grid: #e2e8f0;
  --chart-axis: #64748b;
  --chart-track: #f1f5f9;
}

[data-theme="light"] {
  color-scheme: light;
}

[data-theme="dark"],
html[data-theme="dark"],
body[data-theme="dark"] {
  color-scheme: dark;

  --bg-primary: #090d16;
  --bg-secondary: #0d1424;
  --bg-tertiary: #131c30;
  --bg-card: #141b2d;
  --bg-card-hover: #1c263d;
  --bg-glass: rgba(9, 13, 22, 0.86);
  --surface-card: #141b2d;
  --bg-panel: #141b2d;

  --border-color: rgba(255, 255, 255, 0.09);
  --border-hover: rgba(255, 255, 255, 0.18);
  --border-color-hover: rgba(255, 255, 255, 0.18);
  --border-glow: rgba(229, 72, 77, 0.25);

  --text-primary: #f8fafc;
  --text-secondary: #94a3b8;
  --text-muted: #64748b;
  --text-color: #f8fafc;

  --accent-coral: #f4595e;
  --accent-coral-hover: #ff6b70;
  --accent-coral-subtle: rgba(229, 72, 77, 0.12);
  --accent-coral-line: rgba(229, 72, 77, 0.32);
  --accent-coral-glow: rgba(229, 72, 77, 0.18);

  --accent-green: #34d399;
  --accent-green-subtle: rgba(16, 185, 129, 0.10);
  --accent-green-line: rgba(16, 185, 129, 0.28);
  --accent-amber: #fbbf24;
  --accent-amber-subtle: rgba(251, 191, 36, 0.10);
  --accent-amber-line: rgba(251, 191, 36, 0.28);
  --accent-blue: #60a5fa;
  --accent-blue-subtle: rgba(96, 165, 250, 0.10);
  --accent-blue-line: rgba(96, 165, 250, 0.28);
  --accent-teal: #2dd4bf;

  --shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.30);
  --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.36), 0 1px 2px -1px rgba(0, 0, 0, 0.30);
  --shadow-md: 0 12px 28px -8px rgba(0, 0, 0, 0.55), 0 4px 10px -4px rgba(0, 0, 0, 0.40);
  --shadow-lg: 0 24px 56px -16px rgba(0, 0, 0, 0.65), 0 8px 20px -8px rgba(0, 0, 0, 0.45);
  --shadow-glow: none;

  /* Dark chart steps are selected against the dark card surface, not flipped
     from the light ones. The light ramp is too dark here and the text-tuned
     dark accents are too light — both fail the band. */
  --chart-1: #ef4444;
  --chart-2: #3b82f6;
  --chart-3: #10a672;
  --chart-4: #d97706;
  --chart-5: #0d9488;

  --chart-grid: rgba(255, 255, 255, 0.10);
  --chart-axis: #94a3b8;
  --chart-track: rgba(255, 255, 255, 0.08);
}

/* Section rhythm steps down with the viewport — one token, not thirty
   different paddings. */
@media (max-width: 1023.98px) {
  :root { --section-py: 64px; --gutter: 20px; }
}

@media (max-width: 767.98px) {
  :root { --section-py: 48px; --gutter: 16px; }
}

/* ...and steps back up on wide screens. Content grows to about 1600px and then
   stops: past that the eye loses the start of the line it is reading.

   1560/1880 rather than the round 1600/1920 because Windows Chrome and Edge
   reserve ~15px for a classic scrollbar, so a *maximized* 1920px window reports
   about 1905px to a min-width query. `min-width: 1920px` would never fire on
   the exact display this exists for. These two values also correctly stay quiet
   at 1536px (a 125%-scaled 1920 laptop) and 1512px (13" MacBook Air). */
@media (min-width: 1560px) {
  :root {
    --max-width: 1440px;
    --max-width-nav: 1440px;
    --gutter: 32px;
    --section-py: 112px;
  }
}

@media (min-width: 1880px) {
  :root {
    --max-width: 1600px;
    --max-width-nav: 1600px;
    --gutter: 40px;
    --section-py: 128px;
  }
}

/* The three "fluid" type steps top out between 743px and 800px, so from a small
   laptop to a 27" monitor the hero headline has been a flat 56px. This resumes
   the climb.

   The coefficients are chosen so each clamp evaluates to exactly its old
   ceiling at 1280px — nothing jumps at the breakpoint — and reaches its new
   maximum at exactly 1920px, so a 2560px monitor shows the same size as a
   1920px one. Checks: 22 + 0.009375x1280 = 34, 28 + 0.0125x1280 = 44,
   40 + 0.0125x1280 = 56. All of this assumes 1rem = 16px, which styles.css
   pins explicitly. */
@media (min-width: 1280px) {
  :root {
    --text-2xl: clamp(2.125rem, 1.375rem + 0.9375vw, 2.5rem);   /* 34 -> 40 */
    --text-3xl: clamp(2.75rem,  1.75rem  + 1.25vw,   3.25rem);  /* 44 -> 52 */
    --text-4xl: clamp(3.5rem,   2.5rem   + 1.25vw,   4rem);     /* 56 -> 64 */
  }
}

/* --------------------------------------------------------------------------
   One shared primitive lives here with the tokens, because every surface
   links this file: an icon takes the size and the colour of the text it
   sits beside, so a container that used to size an emoji with font-size
   keeps working.
   -------------------------------------------------------------------------- */

.pc-icon {
  display: inline-block;
  width: 1em;
  height: 1em;
  vertical-align: -0.125em;
  flex: none;
}


/* --------------------------------------------------------------------------
   Avatar — the one identity disc, shared by the header, the dashboard, the
   account page and the admin console.

   Two rules it exists to enforce:

   1. Initials are accent ink on a tint, never white on a solid accent. White
      on the dark-theme green and blue steps lands near 1.9:1, which is why
      every surface that rolled its own disc kept failing contrast.
   2. A picture is optional. When one is set it covers the disc; when it is
      absent, fails to load, or is still loading, the initials underneath are
      what shows. No JavaScript is needed for that fallback.

   Size comes from --pc-avatar-size so a caller can ask for 26px in the nav or
   52px on a profile without redefining the component.
   -------------------------------------------------------------------------- */

.pc-avatar {
  --pc-avatar-size: 38px;
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: var(--pc-avatar-size);
  height: var(--pc-avatar-size);
  border-radius: 50%;
  overflow: hidden;
  background: var(--accent-green-subtle);
  color: var(--accent-green);
  font-family: var(--font-ui);
  font-weight: 700;
  font-size: calc(var(--pc-avatar-size) * 0.42);
  line-height: 1;
  letter-spacing: 0;
  text-transform: uppercase;
  user-select: none;
}

/* The five stable tints. A person keeps one colour wherever you meet them, so
   callers derive the step from a stable key (id or email), never at random. */
.pc-avatar[data-tint="green"] { background: var(--accent-green-subtle); color: var(--accent-green); }
.pc-avatar[data-tint="blue"]  { background: var(--accent-blue-subtle);  color: var(--accent-blue); }
.pc-avatar[data-tint="amber"] { background: var(--accent-amber-subtle); color: var(--accent-amber); }
.pc-avatar[data-tint="coral"] { background: var(--accent-coral-subtle); color: var(--accent-coral); }
.pc-avatar[data-tint="slate"] { background: var(--bg-tertiary);         color: var(--text-secondary); }

/* The picture layer. Absent src, or a broken one, and this paints nothing —
   the initials behind it stay visible. */
.pc-avatar-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: inherit;
  display: block;
}

.pc-avatar-img:not([src]),
.pc-avatar-img[src=""] {
  display: none;
}

.pc-avatar-initials {
  position: relative;
  z-index: 0;
}

/* --------------------------------------------------------------------------
   Avatar picker — the placeholder a person taps to add their picture.
   -------------------------------------------------------------------------- */

.pc-avatar-picker {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  flex-wrap: wrap;
}

.pc-avatar-picker .pc-avatar {
  --pc-avatar-size: 72px;
}

/* The dashed ring reads as an empty slot waiting for something, and it is
   dropped the moment a picture is actually set. */
.pc-avatar-picker .pc-avatar[data-has-image="false"] {
  box-shadow: 0 0 0 2px var(--bg-primary), 0 0 0 3px var(--border-color);
}

.pc-avatar-picker-body {
  min-width: 0;
}

.pc-avatar-picker-title {
  margin: 0 0 2px;
  font-size: var(--text-base);
  font-weight: 700;
  letter-spacing: var(--tracking-snug);
  color: var(--text-primary);
}

.pc-avatar-picker-hint {
  margin: 0 0 var(--space-3);
  font-size: var(--text-sm);
  line-height: var(--leading-snug);
  color: var(--text-muted);
}

.pc-avatar-picker-actions {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex-wrap: wrap;
}

.pc-avatar-btn {
  padding: 8px 14px;
  border: 1px solid var(--border-color);
  border-radius: var(--radius-md);
  background: var(--bg-card);
  color: var(--text-primary);
  font-family: var(--font-ui);
  font-size: var(--text-sm);
  font-weight: 700;
  cursor: pointer;
  transition: border-color var(--transition-fast), background var(--transition-fast), color var(--transition-fast);
}

.pc-avatar-btn:hover {
  border-color: var(--accent-coral-line);
  background: var(--accent-coral-subtle);
  color: var(--accent-coral);
}

.pc-avatar-btn[hidden] {
  display: none;
}

.pc-avatar-picker input[type="file"] {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}

.pc-avatar-picker-note {
  margin: var(--space-2) 0 0;
  font-size: var(--text-xs);
  color: var(--text-muted);
}

/* --------------------------------------------------------------------------
   Avatar picker — drop state and the framing dialog.

   The picker is also a dropzone, because dropping a photo onto the disc is
   what people try before they look for a button. The frame dialog exists for
   one reason: a disc is a circle, and an uncropped phone photo puts the face
   somewhere off to one side of it.
   -------------------------------------------------------------------------- */

.pc-avatar-picker {
  position: relative;
  padding: var(--space-3);
  margin: calc(var(--space-3) * -1);
  border: 1px dashed transparent;
  border-radius: var(--radius-lg);
  transition: border-color var(--transition-fast), background var(--transition-fast);
}

.pc-avatar-picker.dragover {
  border-color: var(--accent-coral-line);
  background: var(--accent-coral-subtle);
}

.pc-crop-overlay {
  position: fixed;
  inset: 0;
  z-index: 9999;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-4);
  background: rgba(15, 23, 42, 0.55);
}

.pc-crop-panel {
  width: 100%;
  max-width: 340px;
  padding: var(--space-5);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-xl);
  background: var(--bg-card);
  box-shadow: var(--shadow-lg);
  text-align: center;
}

.pc-crop-title {
  margin: 0 0 var(--space-1);
  font-family: var(--font-display);
  font-size: var(--text-md);
  font-weight: 700;
  color: var(--text-primary);
}

.pc-crop-hint {
  margin: 0 0 var(--space-4);
  font-size: var(--text-xs);
  color: var(--text-muted);
}

/* The canvas is square; the circle is drawn over it so what you drag is
   exactly what the disc will show. */
.pc-crop-stage {
  position: relative;
  width: 260px;
  max-width: 100%;
  aspect-ratio: 1;
  margin: 0 auto;
  overflow: hidden;
  border-radius: var(--radius-full);
  background: var(--bg-tertiary);
  cursor: grab;
  touch-action: none;
}

.pc-crop-stage:active {
  cursor: grabbing;
}

.pc-crop-canvas {
  display: block;
  width: 100%;
  height: 100%;
}

.pc-crop-zoom {
  width: 100%;
  margin: var(--space-4) 0 var(--space-4);
  accent-color: var(--accent-coral);
}

.pc-crop-actions {
  display: flex;
  gap: var(--space-2);
  justify-content: center;
}

.pc-avatar-btn-primary {
  border-color: var(--accent-coral);
  background: var(--accent-coral);
  color: #fff;
}

.pc-avatar-btn-primary:hover {
  border-color: var(--accent-coral-hover);
  background: var(--accent-coral-hover);
  color: #fff;
}

@media (prefers-reduced-motion: reduce) {
  .pc-avatar-picker {
    transition: none;
  }
}

/* The header is sticky, so an anchor jump would otherwise land the picker
   underneath it. */
#profile-photo {
  scroll-margin-top: 88px;
}
