/* ============================================================================
   HOME DASHBOARD (/app/)

   A main column and a right rail: what to do next down the main, how the
   practice is going in the rail, which sticks while the main scrolls.

     ┌──────────────────────────────┬─────────────┐
     │ up next (hero)               │ the funnel  │
     ├──────────────────────────────┤ + the drops │
     │ recent / needs attention     │ + the rate  │
     │   · row                      ├─────────────┤
     │   · row                      │ completed   │
     │   · row                      │ per month   │
     └──────────────────────────────┴─────────────┘

   Everything here is scoped under .dash so it cannot leak into a ported
   section sharing the same region.

   Font sizes are in px rather than the rem type tokens. platform-tokens.css
   sets html { font-size: 80% }, so --text-small paints 11.2px and --text-meta
   10.4px, a fifth under what their names and comments advertise. Body copy at
   10px is not a style choice, it is a bug in disguise — so the scale is stated
   directly and the numbers below are the sizes that actually render. That is
   the only scaling this file does: the shell's 0.67 density is gone, and these
   are the platform's own sizes, not a fraction of them.
   ============================================================================ */

/* ---- head ---------------------------------------------------------------- */

.dash__head {
    display: flex;
    align-items: flex-end;
    flex-wrap: wrap;
    gap: var(--space-4, 16px);
    margin-bottom: var(--space-6, 24px);
}

/* Date over greeting, as one block. The quick actions still sit opposite it,
   so the row is two columns rather than four inline items. */
.dash__intro {
    display: flex;
    flex-direction: column;
    gap: var(--space-1, 4px);
    min-width: 0;
}

.dash__greeting {
    margin: 0;
    font-family: var(--font-heading, 'Fraunces', Georgia, serif);
    font-weight: var(--font-bold, 700);
    /* Hero scale, in px on purpose. The root font-size here is 12.8px, so a
       rem token renders a fifth smaller than its name claims (--text-h1's
       "2rem" lands at 25.6px) — see the note at the top of this file. clamp
       keeps it from swallowing a narrow viewport. */
    font-size: clamp(31px, 6.3vw, 46px);
    line-height: 1.1;
    letter-spacing: -1.5px;
    color: var(--color-ink, #2C2416);
}

/* The eyebrow: italic, so it reads as the brand's accent voice rather than a
   second heading competing with the name below it. */
.dash__date {
    font-style: italic;
    font-size: 13px;
    color: var(--color-ink-secondary, #5C5242);
    white-space: nowrap;
}

.dash__quick {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2, 8px);
    margin-left: auto;
}

/* The `.dash__q` pill that used to live here is gone: with the row down to two
   actions they are the page's calls to action, not quiet shortcuts, so they are
   ws_button primary. The container stays — it is the layout, not the styling. */

/* ---- main and rail -------------------------------------------------------- */

/* A main column and a fixed-width right rail.

   The old shape was two proportional columns, 1.55fr against 1fr, which is a
   two-column layout rather than a rail: the second column was 494px of mostly
   air, 334px tall against the main column's 531px, so it ran out a third of the
   way up and left the page ending 611px into a 1250px frame. A rail is a stated
   width, and the main column takes whatever is left.

   The three children are placed explicitly rather than flowing, so the rail can
   sit between the decision and the list in the DOM — where a screen reader
   meets it in a sensible order — while still painting down the right of both. */
.dash__grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 340px;
    grid-template-rows: auto 1fr;
    column-gap: var(--space-5, 20px);
    align-items: start;
}

.dash__main  { grid-column: 1; grid-row: 1; min-width: 0; }
.dash__lists { grid-column: 1; grid-row: 2; min-width: 0; margin-top: var(--space-6, 24px); }

/* Sticky, so the funnel stays on screen while a long list scrolls under it.
   The frame's main is the scroll container, so the offset is from its top. */
.dash__rail {
    grid-column: 2;
    grid-row: 1 / span 2;
    position: sticky;
    top: var(--space-1, 4px);
    min-width: 0;
}

.dash__rail > .dash__viz:first-child { margin-top: 0; }

/* Under 1080px the rail stops being a rail: it unsticks and drops under the
   main column at full width, measures after the thing they measure. */
@media (max-width: 1080px) {
    .dash__grid { grid-template-columns: 1fr; grid-template-rows: auto auto auto; }
    .dash__main  { grid-row: 1; }
    .dash__lists { grid-row: 2; }
    .dash__rail  {
        grid-column: 1;
        grid-row: 3;
        position: static;
        margin-top: var(--space-6, 24px);
    }
}

/* ---- up next ------------------------------------------------------------- */

/* The one card on the page that is not white. It carries the single decision
   the dashboard exists to make, so it gets the brand gradient and everything
   else stays paper and ink. */
.dash__hero {
    position: relative;
    overflow: hidden;
    display: flex;
    align-items: center;
    gap: var(--space-6, 24px);
    padding: var(--space-6, 24px) var(--space-5, 20px);
    border-radius: var(--radius-xl, 12px);
    color: var(--text-inverse, #FFFFFF);
    background:
        radial-gradient(90% 150% at 85% -10%, rgba(255, 255, 255, 0.20), transparent 55%),
        linear-gradient(135deg, var(--phase-learn, #E54D4D) 0%, #7F1D1D 100%);
}

/* Two soft shapes bled off the top-right corner. Decorative only, and behind
   everything: the text sits on the gradient, never on a highlight.

   z-index is doing real work here, not tidying. Positioned elements at
   z-index:auto paint in DOM order, and ::after comes after the element's own
   children — so without this the second shape lands on top of the title. It
   only shows once the title wraps far enough right to reach it, which is why
   it is invisible on a wide viewport and obvious on a phone. */
.dash__hero::before,
.dash__hero::after {
    content: "";
    position: absolute;
    z-index: 0;
    background: rgba(255, 255, 255, 0.10);
    filter: blur(1px);
    pointer-events: none;
}

.dash__hero::before {
    width: 190px; height: 190px;
    right: 150px; top: -105px;
    border-radius: 50%;
}

.dash__hero::after {
    width: 120px; height: 120px;
    right: 36px; top: 40px;
    border-radius: 28px;
    transform: rotate(18deg);
}

.dash__hero > * { position: relative; z-index: 1; }

.dash__when {
    font-size: 10px;
    font-weight: var(--font-bold, 700);
    letter-spacing: 0.12em;
    text-transform: uppercase;
    opacity: 0.92;
}

/* color stated, not inherited: the global sheet sets a colour on h2 directly,
   and a directly-matching declaration beats an inherited one no matter how
   specific the ancestor. Without this the title renders ink on the gradient. */
.dash__hero-title {
    color: inherit;
    margin: var(--space-1-5, 6px) 0 var(--space-1, 4px);
    font-family: var(--font-heading, 'Fraunces', Georgia, serif);
    font-weight: var(--font-bold, 700);
    font-size: 24px;
    line-height: 1.15;
    letter-spacing: -0.6px;
}

.dash__stage {
    color: inherit;   /* same reason as the title above */
    margin: 0;
    font-size: 13px;
    opacity: 0.94;
}

/* The text column takes the slack so the actions keep their natural width;
   min-width:0 lets a long workshop title wrap instead of forcing the row wide. */
.dash__hero-body {
    flex: 1;
    min-width: 0;
}

/* Stacked, right-hand column. Each chip fills the column so the two read as a
   pair rather than two differently-sized buttons. */
.dash__hero-actions {
    display: flex;
    flex-direction: column;
    gap: var(--space-2-5, 10px);
    flex-shrink: 0;
}

/* ws_button's secondary variant is drawn for the paper background — on the
   hero's red gradient its ink-on-white would be the only white block on the
   card. Same component, repainted for a dark surface: translucent white fill,
   white border, white label. */
.dash__hero-actions .dash__hero-btn {
    justify-content: flex-start;
    white-space: nowrap;
    background: rgba(255, 255, 255, 0.14);
    border-color: rgba(255, 255, 255, 0.55);
    color: var(--text-inverse, #FFFFFF);
}

.dash__hero-actions .dash__hero-btn:hover,
.dash__hero-actions .dash__hero-btn:focus-visible {
    background: rgba(255, 255, 255, 0.24);
    border-color: var(--bg-surface, #FFFFFF);
    color: var(--text-inverse, #FFFFFF);
}

/* One of these icons is a local SVG and the other is a font glyph (there is no
   co_present asset), and left alone they render at 11px and 24px — visibly
   mismatched side by side. Pin both to the same box. */
.dash__hero-actions .ws-btn__icon,
.dash__hero-actions .ws-btn__icon > * {
    width: 18px;
    height: 18px;
    font-size: 18px;
    flex-shrink: 0;
}

/* The hand-rolled .dash__chip that used to sit here is gone: the hero's two
   actions are ws_button secondary now, restyled for the dark card just above. */

/* A white focus ring, since the card is red and the component's own ring is
   drawn for the paper background. */
.dash__hero-actions .dash__hero-btn:focus-visible {
    outline: 2px solid var(--text-inverse, #FFFFFF);
    outline-offset: 1px;
}

/* ---- section heads ------------------------------------------------------- */

.dash__sect {
    display: flex;
    align-items: baseline;
    gap: var(--space-2-5, 10px);
    margin: var(--space-5, 20px) 0 var(--space-2-5, 10px);
}

.dash__sect h2 {
    margin: 0;
    font-size: 12px;
    font-weight: var(--font-bold, 700);
    letter-spacing: 0.11em;
    text-transform: uppercase;
    color: var(--color-ink-secondary, #5C5242);
}

.dash__sect a {
    margin-left: auto;
    font-size: 13px;
    font-weight: var(--font-semibold, 600);
    color: var(--color-error-strong, #B91C1C);
    text-decoration: none;
}

.dash__sect a:hover { text-decoration: underline; }

/* The tabbed variant swaps the uppercase h2 for the tab strip, so the row
   aligns on the tabs' own baseline instead of a heading's, and the strip
   keeps its underline flush with the list below it. */
.dash__sect--tabs {
    align-items: flex-end;
    gap: var(--space-4, 16px);
    margin-bottom: 0;
    border-bottom: 1px solid var(--gray-200, #E7E5E4);
}

.dash__sect--tabs .ws-tabs {
    flex: 1;
    min-width: 0;
    margin-bottom: -1px;   /* sit the active underline on the section rule */
}

/* The lg variant's own font-size is a rem token, which lands at 12px against
   this shell's 12.8px root — bigger padding, same small label. State it in px,
   like the rest of this file.
   These read as the section's headings, so they are sized against the h2s they
   replaced rather than as controls. */
.dash__sect--tabs .ws-tabs__btn {
    font-family: var(--font-heading, 'Fraunces', Georgia, serif);
    font-size: 19px;
    font-weight: var(--font-bold, 700);
    letter-spacing: -0.45px;
    padding: var(--space-2, 8px) 0 var(--space-3, 12px);
    text-transform: none;
}

/* Gap between the two tabs, now that the padding no longer supplies it. */
.dash__sect--tabs .ws-tabs__nav {
    gap: var(--space-6, 24px);
}

.dash__sect--tabs .ws-tabs__count {
    font-family: var(--font-body, 'Inter', sans-serif);
    font-size: 12px;
    font-weight: var(--font-semibold, 600);
}

.dash__sect--tabs a {
    padding-bottom: var(--space-2-5, 10px);
    white-space: nowrap;
}

/* Panes carry their own top space now the section rule sits directly above. */
.dash__sect--tabs + .ws-tab-pane,
.ws-tab-pane + .ws-tab-pane {
    margin-top: var(--space-4, 16px);
}

/* ---- needs attention -------------------------------------------------------
   Nothing here. This section held .dash__list, .dash__row and its parts
   (.dash__thumb, .dash__row-body, .dash__row-title, .dash__row-detail,
   .dash__cta) plus a .dash__phase* journey strip: about 190 lines
   describing the hand-rolled queue this dashboard drew before both panes
   moved to ws_workshop_list(). None of those classes appears in
   app/views/home.php or app/includes/dashboard.php any more, and the
   listing paints .wl-* from app/css/workshop-list.css instead.
   ---------------------------------------------------------------------------- */

/* ---- the right column ---------------------------------------------------- */

/* ws_task_checklist ships as its own card — white, bordered, padded — which
   inside these panels is a card within a card, and the white undid the paper.
   It drops its chrome here and lets the panel around it be the card. Scoped
   rather than changed at the component: MyWorkshopr's overview panel uses the
   checklist standalone and still wants the card. */
.dash__journey .ws-task-checklist,
.dash__firstrun .ws-task-checklist {
    background: transparent;
    border: 0;
    border-radius: 0;
    padding: 0;
}

.dash__viz {
    /* A column, so .dash__split's margin-top:auto can hold the rate against
       the bottom of the card whatever the funnel above it measures. */
    display: flex;
    flex-direction: column;
    padding: var(--space-4, 16px) var(--space-5, 20px);
    /* Paper, as the rows are: one surface across the whole dashboard rather
       than white panels beside paper rows. */
    background: var(--bg-paper, #FAF7F2);
    border: 1px solid var(--gray-200, #E7E5E4);
    border-radius: var(--radius-lg, 8px);
    box-shadow: var(--shadow-xs, 0 0.7px 2px rgba(0, 0, 0, 0.06));
}

.dash__viz + .dash__viz { margin-top: var(--space-4, 16px); }

.dash__viz h2 {
    margin: 0 0 var(--space-3, 12px);
    font-size: 12px;
    font-weight: var(--font-bold, 700);
    letter-spacing: 0.11em;
    text-transform: uppercase;
    color: var(--color-ink-secondary, #5C5242);
}

/* ---- the funnel ----------------------------------------------------------- */

/* Three bars off a shared zero with the two drops named between them.

   The ramp is ordinal, not one flat red. Funnel stages are a sequence — swap
   two and the meaning changes — so the order belongs in the hue as well as in
   the vertical position, light to dark along the journey. That also puts the
   strongest mark on the smallest bar, which is what makes a count of 1 read at
   2% of the track. The mid and dark steps are the platform's own --phase-learn
   pair; only --dash-funnel-1 is new, and the three validate as an ordinal ramp
   against --bg-paper: monotone lightness, adjacent ΔL >= 0.06, light end at
   2.11:1 on the surface, hue spread 5°. */
.dash {
    --dash-funnel-1: #F09393;
    --dash-funnel-2: var(--phase-learn, #E54D4D);
    --dash-funnel-3: var(--phase-learn-dark, #C73E3E);
}

.dash__stages { margin-bottom: var(--space-4, 16px); }

.dash__frow {
    display: grid;
    grid-template-columns: 82px 1fr;
    align-items: center;
    gap: var(--space-2-5, 10px);
}

.dash__fl {
    font-size: 12px;
    color: var(--color-ink-secondary, #5C5242);
}

/* No boxed track. A bordered, filled track draws a rectangle of ink around
   every bar and reads as a meter against a limit; these are three bars on one
   shared scale, so the baseline and the bar are the whole mark. */
/* The right padding is the gutter the tip label sits in. Bar widths are a
   percentage of the content box, so reserving the gutter here scales every bar
   by the same factor and keeps the ratios exact — capping the longest bar with
   a max-width instead would shorten only that one and quietly misstate it. The
   label is laid out after the bar and overhangs into the gutter, which is what
   the room is for. */
.dash__ftrack {
    display: flex;
    align-items: center;
    gap: var(--space-2, 8px);
    padding-right: 40px;
    min-width: 0;
}

.dash__fbar {
    flex: 0 0 auto;
    height: 18px;
    /* A count of 1 against a max of 47 is 2% of the track. Never let a real
       value paint as nothing. */
    min-width: 4px;
    /* Square where it leaves the baseline, rounded at the data end. */
    border-radius: 0 var(--radius-sm, 4px) var(--radius-sm, 4px) 0;
    background: var(--dash-funnel-1);
}

.dash__fbar--2 { background: var(--dash-funnel-2); }
.dash__fbar--3 { background: var(--dash-funnel-3); }

.dash__fbar.is-zero { min-width: 0; }

/* The value rides the tip of its own bar. In a fixed right-hand column the
   number for a 2%-wide bar sat half a card away from the mark it belonged to.
   Proportional figures, not tabular: these do not align in a column any more. */
.dash__fv {
    flex: 0 0 auto;
    font-size: 13px;
    font-weight: var(--font-bold, 700);
    line-height: 1;
    color: var(--color-ink, #2C2416);
}

/* The drop between two stages, named. Indented to the bar column so it reads
   as the gap between the two bars it sits between rather than as a caption. */
.dash__drop {
    display: flex;
    align-items: center;
    gap: var(--space-2, 8px);
    margin: var(--space-1, 4px) 0 var(--space-1, 4px) 92px;
    font-size: 11px;
    color: var(--color-ink-secondary, #5C5242);
}

.dash__drop-rule {
    flex: 0 0 auto;
    width: 1px;
    height: 14px;
    margin-left: 3px;
    background: var(--gray-300, #D6D3D1);
}

.dash__drop-text strong {
    font-weight: var(--font-bold, 700);
    color: var(--color-ink, #2C2416);
}

/* Solid hairline. A dashed rule reads as a threshold or a projection; this is
   just where the card changes subject. */
.dash__split {
    margin-top: auto;
    padding-top: var(--space-3-5, 14px);
    border-top: 1px solid var(--gray-200, #E7E5E4);
}

/* The one hero figure on the page. Ink, not the error token — a synthesis rate
   is a measure, not a fault, and --color-error-strong made a healthy 50% read
   as a warning. 60px against the frame's 0.8 zoom lands at 48px on screen.
   Proportional figures: tabular ones give every digit the width of a zero,
   which makes a standalone number look loose at this size. */
.dash__num {
    display: block;
    font-size: 60px;
    font-weight: var(--font-bold, 700);
    line-height: 1;
    letter-spacing: -0.03em;
    color: var(--color-ink, #2C2416);
}

.dash__sub {
    margin: var(--space-1, 4px) 0 0;
    font-size: 12px;
    color: var(--color-ink-secondary, #5C5242);
}

/* ---- the monthly trend ---------------------------------------------------- */

/* Columns, not a line. The line drew segments between months, which claims the
   months in between hold intermediate values; a full-lifecycle workshop either
   completed in a given month or it did not. Columns also fail gracefully — five
   empty slots and one column reads as "one happened", where the same data as a
   line ran along the floor and then leapt off it, which reads as a chart that
   broke. Drawn in CSS, so the marks wear tokens instead of the five hardcoded
   hexes the SVG carried.

   The old SVG was capped at 316px because its labels were drawn in user units
   and magnified when the viewBox stretched. HTML text does not scale with the
   box, so the chart fills the rail. */
.dash__cols {
    display: flex;
    align-items: flex-end;
    gap: var(--space-1-5, 6px);
    padding-bottom: var(--space-1-5, 6px);
    /* The baseline is the axis: one hairline, solid, a step off the surface. */
    border-bottom: 1px solid var(--gray-200, #E7E5E4);
}

.dash__col {
    flex: 1 1 0;
    min-width: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-1, 4px);
}

/* A stated height so the bars have something to be a percentage of, and so the
   x-axis band sits inside the card rather than being cropped out of it. */
.dash__col-plot {
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    align-items: center;
    width: 100%;
    height: 76px;
}

.dash__col-val {
    font-size: 11px;
    font-weight: var(--font-bold, 700);
    line-height: 1;
    margin-bottom: 3px;
    color: var(--color-ink, #2C2416);
}

/* Capped rather than filling the slot: the leftover width is the air between
   columns. Square at the baseline, rounded at the data end. */
.dash__col-bar {
    width: 100%;
    max-width: 22px;
    min-height: 3px;
    border-radius: var(--radius-sm, 4px) var(--radius-sm, 4px) 0 0;
    background: var(--dash-funnel-1);
}

/* The month you are in wears the strong step; the five behind it are context.
   One series, so identity comes from position, not from six hues. */
.dash__col.is-current .dash__col-bar { background: var(--dash-funnel-3); }

.dash__col-label {
    font-size: 11px;
    line-height: 1;
    color: var(--color-ink-secondary, #5C5242);
}

.dash__col.is-current .dash__col-label {
    font-weight: var(--font-bold, 700);
    color: var(--color-ink, #2C2416);
}

/* ---- empty ---------------------------------------------------------------- */

.dash__empty {
    background: var(--bg-paper, #FAF7F2);
    border: 1px solid var(--gray-200, #E7E5E4);
    border-radius: var(--radius-lg, 8px);
    padding: var(--space-6, 24px);
}

/* ---- first run ------------------------------------------------------------ */

.dash__firstrun {
    max-width: 560px;
}

.dash__firstrun-cta { margin-top: var(--space-5, 20px); }

@media (max-width: 700px) {
    .dash__head { gap: var(--space-2, 8px); }
    .dash__quick { margin-left: 0; width: 100%; }

    /* Side by side leaves neither column enough room on a phone, so the
       actions go back under the text and sit as a row. */
    .dash__hero {
        display: block;
    }
    .dash__hero-actions {
        flex-direction: row;
        flex-wrap: wrap;
        margin-top: var(--space-4, 16px);
    }

    /* The tab strip scrolls on its own; "All workshops" drops under it rather
       than being held on the same line by its nowrap and pushed off the edge. */
    .dash__sect--tabs {
        flex-wrap: wrap;
        align-items: stretch;
        border-bottom: none;
    }
    .dash__sect--tabs .ws-tabs {
        flex: 1 1 100%;
        margin-bottom: 0;
        border-bottom: 1px solid var(--gray-200, #E7E5E4);
    }
    .dash__sect--tabs a {
        margin-left: 0;
        padding-bottom: 0;
    }
    /* 20px puts the second tab past the right edge on a 375px screen. The strip
       scrolls, but a half-visible "Needs attentio…" reads as broken rather than
       scrollable, so both labels are sized to fit instead. */
    .dash__sect--tabs .ws-tabs__btn {
        font-size: 16px;
    }
    .dash__sect--tabs .ws-tabs__nav {
        gap: var(--space-4, 16px);
    }

    /* The narrow-width reflow for .dash__row went with the row itself; see the
       note in the "needs attention" section above. ws_workshop_list() carries
       its own breakpoints in app/css/workshop-list.css. */
}
