/* Palette - every colour on the page is named here; the rest of the file
   (and the SVG artwork in index.html) only ever refers to these names.

   Role tokens (--canvas, --panel, --panel-hover, --text, --machine-ink,
   --machine-grey, --encrypted-grey, --blue, --red, --cyan, --yellow,
   --orange) are redefined per theme below. Every role-token value is
   written as an explicit color-mix() against --ink or --white, even where
   the mix is a no-op (0% or 100%) - the point is a single scannable,
   directly-tweakable percentage per token rather than a mix of bare var()
   passthroughs and color-mix() calls. Light and dark are NOT a strict
   mirror of each other; --panel/--panel-hover/--text/--canvas are each
   picked deliberately per theme (see the theme blocks below) rather than
   derived from a shared formula. --panel/--panel-hover are shared by every
   interactive surface on the page (FAB icon-buttons and SVG hotspot
   triggers alike) so hover/focus reads the same everywhere. */

:root {
    /* the two bases: every neutral below is a tint of one or the other */
    --ink: #001;
    --white: #fff;

    /* brand hues, theme-independent - the theme blocks below mix these
       toward --white or --ink for the role tokens (--blue, --red, --cyan,
       --yellow, --orange) */
    --brand-blue: #07e;      /* healthy machines, barrier lines and buttons */
    --brand-red: #c00;       /* virus body, malware tails, encryption locks */
    --brand-cyan: #0cf;      /* links */
    --brand-yellow: #fc0;    /* stolen data/credential icons and trails, highlighted heading, gutter hover */
    --brand-orange: #f80;    /* dropper drops, virus detail, countdown clocks */

    /* percent of the app-shell's height the diagram occupies; the card gets
       the remainder. Drives .diagram-column/.infographic/.card-stack below. */
    --diagram-ratio: 80;
}

/* Light theme (default) - --canvas/--panel/--text/--panel-hover are chosen
   to match the FAB button's own states (see .icon-button below): --panel
   is the resting background for every interactive surface (FABs and SVG
   hotspot triggers alike), --panel-hover their shared hover/focus
   background, --text the FAB icon colour. --encrypted-grey sits at a fixed
   50% ink in both themes (its own mirror) rather than following any
   per-theme choice - the finale state isn't meant to lean light or dark,
   just uniformly dead. */
:root {
    --canvas: color-mix(in srgb, var(--ink) 10%, var(--white));         /* infographic background */
    --panel: color-mix(in srgb, var(--ink) 5%, var(--white));           /* card + FAB resting background */
    --panel-hover: color-mix(in srgb, var(--ink) 0%, var(--white));     /* FAB/trigger hover+focus background - lighter than resting */
    --text: color-mix(in srgb, var(--ink) 95%, var(--white));           /* text, headings, and FAB icon colour */

    --machine-ink: color-mix(in srgb, var(--ink) 100%, var(--white));   /* attacker laptop, drawn on the canvas */
    --machine-grey: color-mix(in srgb, var(--ink) 70%, var(--white));   /* the people at the machines */
    --encrypted-grey: color-mix(in srgb, var(--ink) 50%, var(--white));

    --blue: color-mix(in srgb, var(--brand-blue) 100%, var(--white));
    --red: color-mix(in srgb, var(--brand-red) 100%, var(--white));
    --cyan: color-mix(in srgb, var(--brand-cyan) 55%, var(--ink));      /* darkened for contrast on the light panel */
    --yellow: color-mix(in srgb, var(--brand-yellow) 100%, var(--white));
    --orange: color-mix(in srgb, var(--brand-orange) 100%, var(--white));
}

/* Dark theme - like the light block above, --panel/--panel-hover/--text are
   chosen to match the FAB button's own states rather than following a
   mirror formula from the light theme. */
:root[data-theme="dark"] {
    --canvas: color-mix(in srgb, var(--ink) 95%, var(--white));
    --panel: color-mix(in srgb, var(--ink) 85%, var(--white));           /* FAB resting background */
    --panel-hover: color-mix(in srgb, var(--ink) 70%, var(--white));     /* FAB hover/focus background - lighter than resting */
    --text: color-mix(in srgb, var(--ink) 5%, var(--white));             /* text, headings, and FAB icon colour */

    --machine-ink: color-mix(in srgb, var(--ink) 0%, var(--white));
    --machine-grey: color-mix(in srgb, var(--ink) 30%, var(--white));
    --encrypted-grey: color-mix(in srgb, var(--ink) 50%, var(--white));

    --blue: color-mix(in srgb, var(--brand-blue) 75%, var(--white));    /* lightened for contrast on the dark canvas */
    --red: color-mix(in srgb, var(--brand-red) 75%, var(--white));
    --cyan: color-mix(in srgb, var(--brand-cyan) 100%, var(--white));   /* already bright enough on the dark panel */
    --yellow: color-mix(in srgb, var(--brand-yellow) 100%, var(--white));
    --orange: color-mix(in srgb, var(--brand-orange) 100%, var(--white));
}


/* Reset */

*, html, body {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}


/* Typography */

/* Root font-size scales fluidly with viewport width so the rest of the
   page's em-based sizing stays proportionate on narrow/mobile screens
   instead of overwhelming the fixed 20%-height band, and grows back
   toward 16px on wide desktops. Anchored 14px at 1100px, 16px at 1920px;
   flat beyond either end. */
html {
    font-size: clamp(14px, 11.317px + 0.244vw, 16px);
}

body {
    background-color: var(--panel);
    color: var(--text);
    font-family: "Roboto", sans-serif;
}

h1, h2 {
    font-weight: 500;
    color: var(--text);
    margin-bottom: 0.75em;
    line-height: 1.25;
}

h1 {
    font-size: 1.75em;
}

/* card heading has its own fluid range (16-18px) rather than the em-based
   scaling above, using the same 1100px/1920px anchors as the root clamp */
h2 {
    font-size: clamp(16px, 13.317px + 0.244vw, 18px);
}

p {
    font-size: 1em;
    font-weight: 300;
    line-height: 1.75;
}

p.subtitle {
    font-size: 1.25em;
    line-height: 1.5;
}

a {
    color: var(--cyan);
    text-decoration: none;
}

/* Page layout: fixed-height app shell, one fixed ratio at every viewport
   size - the diagram permanently fills the top 80%, a content card the
   bottom 20% (see .card-stack below). There is no page-level scroll and no
   width-driven breakpoint; the same layout runs on desktop and touch. */

html, body {
    height: 100%;
    overflow: hidden;
}

.app-shell {
    background-color: var(--canvas);
    height: 100vh;
    height: 100dvh;
    overflow: hidden;
}

/* one column holding both the diagram and the card, split by height into
   .infographic (top) and .card-stack (bottom) below. */
.diagram-column {
    display: flex;
    flex-direction: column;
    height: 100%;
}

.infographic {
    background-color: var(--canvas);
    flex: 0 0 calc(var(--diagram-ratio) * 1%);
    overflow: hidden;
    position: relative;
}

/* toolbar for icon controls (Home, theme toggle) - width is synced to the
   card-frame's own width by script.js (see the ResizeObserver in script.js),
   and left/right:0 + margin:auto centers that width the same way .card-frame
   centers itself in .card-stack below, so the toolbar and the card always
   land on the same horizontal box. space-between pins Home to the left edge
   and the theme toggle to the right, mirroring the card's own symmetry. */
.diagram-controls {
    position: absolute;
    top: 1rem;
    left: 0;
    right: 0;
    margin: 0 auto;
    padding: 0 1rem;
    z-index: 5;
    display: flex;
    justify-content: space-between;
}

/* FABs (floating action buttons) - a rounded-rect surface matching the
   card's own background, raised off the canvas with elevation. Sized in
   rem (not px) so it stays fluid with the root clamp like the rest of the
   page's type scale; base 2.5rem/1.5rem glyph scaled up one third per the
   user's request. Contrast against the canvas comes purely from --panel
   being a deliberately different step than --canvas - no shadow or border
   crutch needed. */
.icon-button {
    display: flex;
    align-items: center;
    justify-content: center;
    width: calc(2.5rem * 4 / 3);
    height: calc(2.5rem * 4 / 3);
    border: none;
    border-radius: 0.75rem;
    background-color: var(--panel);
    color: var(--text);
    cursor: pointer;
    transition: background-color 0.2s ease;
}

/* no default browser focus rectangle, ever - same convention as .trigger:focus;
   the state layer below is the only focus/hover affordance */
.icon-button:focus {
    outline: none;
}

/* hover and focus share one state: the FAB background steps to
   --panel-hover, always lighter than the resting --panel */
.icon-button:hover,
.icon-button:focus-visible {
    background-color: var(--panel-hover);
}

.material-symbols-rounded {
    font-size: calc(1.5rem * 4 / 3);
    font-variation-settings:
        "FILL" 1,
        "wght" 400,
        "GRAD" 0,
        "opsz" 24;
}

.infographic svg {
    width: auto;
    height: 100%;
    max-width: 100%;
    display: block;
    margin: 0 auto;

    /* triggers paint before (under) the artwork, so the hover disc appears
       behind the icons; pointer events skip the artwork and land on the
       triggers below */
    pointer-events: none;
}

/* card-stack - a full-width band behind the card (see .card-frame below);
   its own background is what shows either side of the card. Sits a shade
   apart from the canvas above it, with a hairline seam marking the join. */
.card-stack {
    flex: 0 0 calc((100 - var(--diagram-ratio)) * 1%);
    background-color: var(--panel);
    border-top: 1px solid var(--canvas);
}

/* width is intentionally unset here - script.js syncs it inline to the
   SVG's rendered width via ResizeObserver, so the card is always exactly
   as wide as the diagram above it. */
.card-frame {
    position: relative;
    height: 100%;
    overflow: hidden;
    margin: 0 auto;
}

/* card-frame holds a double buffer of two full-size cards; script.js writes
   new content into whichever card is currently hidden below the band and
   slides it up over the visible one with GSAP (yPercent + z-index), so the
   new content visually covers the old rather than replacing it in place. */
.card {
    position: absolute;
    inset: 0;
    background-color: var(--panel);
    padding: 2rem;
    overflow-y: auto;
}

/* same fluid approach as the card heading above, 12-14px range */
.card-body {
    font-size: clamp(12px, 9.317px + 0.244vw, 14px);
    line-height: 1.55;
}

/* SVG artwork */

.barrier-line-muted, .malware, .countdown, .stolen, .lock {
    opacity: 0;
    visibility: hidden;
}

.countdown {
    fill: var(--orange);
}

.lancetta {
    fill: var(--white);
}

.barrier-line, .barrier-line-muted {
    stroke-width: 5;
    stroke-linecap: round;
}

.barrier-line {
    stroke: var(--blue);
}

.barrier-line-muted {
    stroke: var(--panel);
}

.barrier-button {
    fill: var(--blue);
}

.user {
    fill: var(--machine-grey);
}

/* cutout details drawn on top of the yellow data/credential icons - match
   the page background so they read as negative space, not a fixed colour */
.icon-detail {
    fill: var(--canvas);
}

.virus-body {
    fill: var(--red);
}

.virus-detail {
    fill: var(--orange);
}

/* the attacker's laptop, drawn on the canvas */
.machine-ink {
    fill: var(--machine-ink);
}

.lock-body {
    fill: var(--red);
}

.lock rect {
    fill: none;
    stroke: var(--red);
    stroke-width: 3;
    stroke-miterlimit: 10;
}

.device, .workstation {
    fill: var(--blue);
    transition: fill 0.2s;
}

/* machine states, toggled by the barrier timelines in script.js - the tint scale
   (70% ink = the users' grey, 30% = the encrypted grey) is spelled out in the palette.
   .encrypted is declared after .infected so the finale grey wins while both are set */
.infected {
    fill: var(--red);
}

.encrypted {
    fill: var(--encrypted-grey);
}


.trigger {
    cursor: pointer;
    visibility: hidden;
    pointer-events: auto;
}

/* hover on the shape, not the group, so only the icon under the cursor gets the disc.
   Same treatment as the FAB icon-buttons: invisible at rest, full opacity
   on hover/focus. Hover uses --panel-hover (the FAB's hover colour);
   focus/selection uses --panel (the FAB's resting colour) - see below. */
.trigger circle {
    fill: var(--panel);
    fill-opacity: 0; /* invisible but still hit-testable: fill must stay a paint, not 'none' */
    transition: fill-opacity 0.2s ease;
}

.trigger.on {
    visibility: visible;
}

.trigger circle:hover {
    fill: var(--panel-hover);
    fill-opacity: 1;
}

/* keyboard focus and persisted selection (script.js marks a trigger .lit
   when selected, or its paired heading is hovered) read as the FAB's
   normal (not hover) state - a persisted marker should look like a
   resting surface, not a momentary hover. Declared after :hover so it
   wins when a selected hotspot is also under the pointer. Full opacity on
   focus specifically because this is the only focus affordance: the
   default browser outline is suppressed below. */
.trigger:focus-visible circle,
.trigger.lit circle {
    fill: var(--panel);
    fill-opacity: 1;
}

/* ...but a focused/lit circle still lightens further when also hovered -
   the hover affordance never goes dead just because the hotspot is
   already selected. Higher specificity than both rules above. */
.trigger:focus-visible circle:hover,
.trigger.lit circle:hover {
    fill: var(--panel-hover);
}

/* no default browser focus rectangle, ever - clicking (not just keyboard
   focus) leaves the default outline behind unless :focus itself is
   suppressed, not just :focus-visible. The fill-opacity above is the only
   focus/selection affordance. */
.trigger:focus {
    outline: none;
}

.yellow {
    fill: var(--yellow);
}

/* shared gradient ramps (templates in the SVG defs) - the dropper drops fade in
   from transparent, the malware tails ease from the FAB's resting --panel
   tone into the red (so the tail's leading edge stays visibly distinct from
   whichever canvas tone is active, rather than dissolving into it); the
   eased mixes are fixed, so retinting either ramp is a one-variable change */
#drop-stops stop {
    stop-color: var(--orange);
}

#drop-stops stop:first-child {
    stop-opacity: 0;
}

#tail-stops stop:nth-child(1)  { stop-color: var(--panel); }
#tail-stops stop:nth-child(2)  { stop-color: color-mix(in srgb, var(--red) 1.6%, var(--panel)); }
#tail-stops stop:nth-child(3)  { stop-color: color-mix(in srgb, var(--red) 5.8%, var(--panel)); }
#tail-stops stop:nth-child(4)  { stop-color: color-mix(in srgb, var(--red) 13.1%, var(--panel)); }
#tail-stops stop:nth-child(5)  { stop-color: color-mix(in srgb, var(--red) 24.1%, var(--panel)); }
#tail-stops stop:nth-child(6)  { stop-color: color-mix(in srgb, var(--red) 37.7%, var(--panel)); }
#tail-stops stop:nth-child(7)  { stop-color: color-mix(in srgb, var(--red) 54.5%, var(--panel)); }
#tail-stops stop:nth-child(8)  { stop-color: color-mix(in srgb, var(--red) 74.9%, var(--panel)); }
#tail-stops stop:nth-child(9)  { stop-color: color-mix(in srgb, var(--red) 97.4%, var(--panel)); }
#tail-stops stop:nth-child(10) { stop-color: var(--red); }


/* tooltip following the cursor over SVG hotspots */

#tooltip {
    position: fixed;
    background-color: color-mix(in srgb, var(--ink) 85%, transparent);
    color: var(--white);
    font-size: 0.85rem;
    font-weight: 300;
    padding: 0.35em 0.9em;
    border-radius: 1em;
    white-space: nowrap;
    pointer-events: none;
    opacity: 0;
    transition: opacity 0.15s ease;
    z-index: 10;
}

#tooltip.visible {
    opacity: 1;
}

/* the hover tooltip only makes sense on real hover-capable pointers - on touch
   it would otherwise get stuck open after a tap */
@media not (hover: hover) {
    #tooltip {
        display: none;
    }
}


